C/C++ Pthread线程
线程按照其调度者可以分为用户级线程和核心级线程两种
用户级线程主要解决的是上下文切换的问题,它的调度算法和调度过程全部由用户自行选择决定,在运行时不需要特定的内核支持;
我们常用基本就是用户级线程,所以就只总结一下POSIX提供的用户级线程接口;
基本线程操作相关的函数:
1线程的建立结束
2线程的互斥和同步
3使用信号量控制线程
4线程的基本属性配置
基本线程操作:
函数 | 说明 |
---|---|
pthread_create() | 创建线程开始运行相关线程函数,运行结束则线程退出 |
pthread_eixt() | 因为exit()是用来结束进程的,所以则需要使用特定结束线程的函数 |
pthread_join() | 挂起当前线程,用于阻塞式地等待线程结束,如果线程已结束则立即返回,0=成功 |
pthread_cancel() | 发送终止信号给thread线程,成功返回0,但是成功并不意味着thread会终止 |
pthread_testcancel() | 在不包含取消点,但是又需要取消点的地方创建一个取消点,以便在一个没有包含取消点的执行代码线程中响应取消请求. |
pthread_setcancelstate() | 设置本线程对Cancel信号的反应 |
pthread_setcanceltype() | 设置取消状态 继续运行至下一个取消点再退出或者是立即执行取消动作 |
pthread_setcancel() | 设置取消状态 |
互斥与同步机制基本函数
函数 | 说明 |
---|---|
pthread_mutex_init() | 互斥锁的初始化 |
pthread_mutex_lock() | 锁定互斥锁,如果尝试锁定已经被上锁的互斥锁则阻塞至可用为止 |
pthread_mutex_trylock() | 非阻塞的锁定互斥锁 |
pthread_mutex_unlock() | 释放互斥锁 |
pthread_mutex_destory() | 互斥锁销毁函数 |
信号量线程控制(默认无名信号量)
函数 | 说明 |
---|---|
sem_init(sem) | 初始化一个定位在sem的匿名信号量 |
sem_wait() | 把信号量减1操作,如果信号量的当前值为0则进入阻塞,为原子操作 |
sem_trywait() | 如果信号量的当前值为0则返回错误而不是阻塞调用(errno=EAGAIN),其实是sem_wait()的非阻塞版本 |
sem_post() | 给信号量的值加1,它是一个“原子操作”,即同时对同一个信号量做加1,操作的两个线程是不会冲突的 |
sem_getvalue(sval) | 把sem指向的信号量当前值放置在sval指向的整数上 |
sem_destory(sem) | 销毁由sem指向的匿名信号量 |
线程属性配置相关函数
函数 | 说明 |
---|---|
pthread_attr_init() | 初始化配置一个线程对象的属性,需要用pthread_attr_destroy函数去除已有属性 |
pthread_attr_setscope() | 设置线程属性 |
pthread_attr_setschedparam() | 设置线程优先级 |
pthread_attr_getschedparam() | 获取线程优先级 |
基本的线程建立运行pthread_create
/* thread.c */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #define THREAD_NUMBER 3 /*线程数*/
#define REPEAT_NUMBER 5 /*每个线程中的小任务数*/
#define DELAY_TIME_LEVELS 10.0 /*小任务之间的最大时间间隔*/
//
void *thrd_func(void *arg) {
/* 线程函数例程 */
int thrd_num = (int)arg;
int delay_time = ;
int count = ;
printf("Thread %d is starting\n", thrd_num);
for (count = ; count < REPEAT_NUMBER; count++) {
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + ;
sleep(delay_time);
printf("\tThread %d: job %d delay = %d\n",
thrd_num, count, delay_time);
} printf("Thread %d finished\n", thrd_num);
pthread_exit(NULL);
} int main(void) {
pthread_t thread[THREAD_NUMBER];
int no = , res;
void * thrd_ret;
srand(time(NULL));
for (no = ; no < THREAD_NUMBER; no++) {
/* 创建多线程 */
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
if (res != ) {
printf("Create thread %d failed\n", no);
exit(res);
}
} printf("Create treads success\n Waiting for threads to finish...\n");
for (no = ; no < THREAD_NUMBER; no++) {
/* 等待线程结束 */
res = pthread_join(thread[no], &thrd_ret);
if (!res) {
printf("Thread %d joined\n", no);
} else {
printf("Thread %d join failed\n", no);
}
}
return ;
}
例程中循环3次建立3条线程,并且使用pthread_join函数依次等待线程结束;
线程中使用rand()获取随机值随机休眠5次,随意会出现后执行的线程先执行完成;
运行结果:
$ gcc thread.c -lpthread
$ ./a.out
Create treads success
Waiting for threads to finish...
Thread is starting
Thread is starting
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread joined
Thread : job delay =
Thread finished
Thread joined
可以看到,线程1先于线程0执行,但是pthread_join的调用时间顺序,先等待线程0执行;
由于线程1已经早结束,所以线程0被pthread_join等到的时候,线程1已结束,就在等待到线程1时,直接返回;
线程执行的互斥和同步pthread_mutex_lock
在上面的程序中增加互斥锁
/*thread_mutex.c*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #define THREAD_NUMBER 3 /* 线程数 */
#define REPEAT_NUMBER 3 /* 每个线程的小任务数 */
#define DELAY_TIME_LEVELS 10.0 /*小任务之间的最大时间间隔*/
pthread_mutex_t mutex; void *thrd_func(void *arg) {
int thrd_num = (int)arg;
int delay_time = , count = ;
int res;
/* 互斥锁上锁 */
res = pthread_mutex_lock(&mutex);
if (res) {
printf("Thread %d lock failed\n", thrd_num);
pthread_exit(NULL);
}
printf("Thread %d is starting\n", thrd_num);
for (count = ; count < REPEAT_NUMBER; count++) {
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + ;
sleep(delay_time);
printf("\tThread %d: job %d delay = %d\n",
thrd_num, count, delay_time);
}
printf("Thread %d finished\n", thrd_num);
pthread_exit(NULL);
} int main(void) {
pthread_t thread[THREAD_NUMBER];
int no = , res;
void * thrd_ret; srand(time(NULL));
/* 互斥锁初始化 */
pthread_mutex_init(&mutex, NULL);
for (no = ; no < THREAD_NUMBER; no++) {
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
if (res != ) {
printf("Create thread %d failed\n", no);
exit(res);
}
}
printf("Create treads success\n Waiting for threads to finish...\n");
for (no = ; no < THREAD_NUMBER; no++) {
res = pthread_join(thread[no], &thrd_ret);
if (!res) {
printf("Thread %d joined\n", no);
} else {
printf("Thread %d join failed\n", no);
}
}
/****互斥锁解锁***/
pthread_mutex_unlock(&mutex);
pthread_mutex_destroy(&mutex);
return ;
}
在上面的例程中直接添加同步锁pthread_mutex_t;
在线程中加入,于是程序在执行线程程序时;
调用pthread_mutex_lock上锁,发现上锁时候后进入等待,等待锁再次释放后重新上锁;
所以线程程序加载到队列中等待,等待成功上锁后继续执行程序代码;
运行结果
$gcc thread_mutex.c -lpthread
$ ./a.out
Create treads success
Waiting for threads to finish...
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
跟例程1中执行结果不同,线程程序被加载到队列中而不能马上执行,需要等到能够成功上锁;
上锁后,继续执行线程程序,上锁执行;
这样线程被依次执行的情况在实际使用场景中经常出现;
使用场景:
当用户登录后获取秘钥才能继续获取该用户的基本信息时;需要等待登录线程结束后才能继续执行获取用户信息的线程时,
需要调用两条线程,假如是:threadLogin(),threadGetInfo(); 则可以有2种方法实现:
1 此时可以使用互斥锁同时一次性调用完threadLogin()和threadGetInfo();
2 当然也可以不使用互斥锁直接在threadLogin()中登录验证成功后调用threadGetInfo();
相比之下,方式1更加清晰的显示逻辑关系,增加代码可读性可扩展性。
使用信号量控制线程的执行顺序sem_post
修改上面例程,上面的是使用pthread_mutex_lock互斥锁控制线程执行顺序,
使用另外一种线程执行顺序的控制;
/* thread_sem.c */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h> #define THREAD_NUMBER 3
#define REPEAT_NUMBER 3
#define DELAY_TIME_LEVELS 10.0 sem_t sem[THREAD_NUMBER]; void * thrd_func(void *arg) {
int thrd_num = (int)arg;
int delay_time = ;
int count = ;
sem_wait(&sem[thrd_num]);
printf("Thread %d is starting\n", thrd_num);
for (count = ; count < REPEAT_NUMBER; count++) {
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + ;
sleep(delay_time);
printf("\tThread %d: job %d delay = %d\n", thrd_num, count, delay_time);
}
printf("Thread %d finished\n", thrd_num);
pthread_exit(NULL);
} int main(void) {
pthread_t thread[THREAD_NUMBER];
int no = , res;
void * thrd_ret;
srand(time(NULL));
for (no = ; no < THREAD_NUMBER; no++) {
sem_init(&sem[no], , );
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no);
if (res != ) {
printf("Create thread %d failed\n", no);
exit(res);
}
} printf("Create treads success\n Waiting for threads to finish...\n");
sem_post(&sem[THREAD_NUMBER - ]);
for (no = THREAD_NUMBER - ; no >= ; no--) {
res = pthread_join(thread[no], &thrd_ret);
if (!res) {
printf("Thread %d joined\n", no);
} else {
printf("Thread %d join failed\n", no);
}
sem_post(&sem[(no + THREAD_NUMBER - ) % THREAD_NUMBER]);
} for (no = ; no < THREAD_NUMBER; no++) {
sem_destroy(&sem[no]);
}
return ;
}
执行结果,仍然是建立3条线程,每条线程执行时休眠随机时长:
$ gcc thread_sem.c -lpthread
$ ./a.out
Create treads success
Waiting for threads to finish...
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
Thread is starting
Thread : job delay =
Thread : job delay =
Thread : job delay =
Thread finished
Thread joined
执行结果与第2个例程非常相似,只不过教材中进行倒序执行而已;
那么这种方式其实与使用互斥锁相比,代码量可读性基本持平不相上下;
线程的基本属性pthread_attr_setscope
设置属性一般有:
1 绑定属性
2 分离属性
3 堆栈地址
4 堆栈大小
5 优先级
关于绑定属性就是绑定于内核线程;
分离属性主要是讲线程结束后是否马上释放相应的内存;
/* thread_attr.c */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #define THREAD_NUMBER 1
#define REPEAT_NUMBER 3
#define DELAY_TIME_LEVELS 10.0
int finish_flag = ; void * thrd_func(void * arg){
int delay_time = ;
int count = ;
printf("Thread is starting\n");
for (count = ; count < REPEAT_NUMBER; count++) {
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + ;
sleep(delay_time);
printf("\tThread : job %d delay = %d\n", count, delay_time);
}
printf("Thread finished\n");
finish_flag = ;
pthread_exit(NULL);
} int main(void) {
pthread_t thread;
pthread_attr_t attr;
int res = ;
srand(time(NULL));
res = pthread_attr_init(&attr);
if (res != ) {
printf("Create attribute failed\n");
exit(res);
}
res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
res += pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (res != ) {
printf("Setting attribute failed\n");
exit(res);
}
res = pthread_create(&thread, &attr, thrd_func, NULL);
if (res != ) {
printf("Create thread failed\n");
exit(res);
}
pthread_attr_destroy(&attr);
printf("Create tread success\n"); while(!finish_flag){
printf("Waiting for thread to finish...\n");
sleep();
}
return ;
}
在运行前后使用 $ free 命令查看内存前后的使用情况发现:
在线程结束后内存马上被释放;
其实,一般线程的属性直接使用系统默认属性即可;
关于线程的使用,大约就是这样。
C/C++ Pthread线程的更多相关文章
- 【C/C++多线程编程之四】终止pthread线程
多线程编程之终止pthread线程 Pthread是 POSIX threads 的简称,是POSIX的线程标准. 终止线程似乎是多线程编程的最后一步,但绝不是本系列教 ...
- [并发并行]_[线程模型]_[Pthread线程使用模型之三 客户端/服务端模型(Client/Server]
Pthread线程使用模型之三 客户端/服务端模型(Client/Server) 场景 1.在客户端/服务端模型时,客户端向服务端请求一些数据集的操作. 服务端执行执行操作独立的(多进程或跨网络)– ...
- [并发并行]_[线程模型]_[Pthread线程使用模型之二 工作组work crew]
Pthread线程使用模型之二工作组(Work crew) 场景 1.一些耗时的任务,比如分析多个类型的数据, 是独立的任务, 并不像 pipeline那样有序的依赖关系, 这时候pipeline就显 ...
- [并发并行]_[线程模型]_[Pthread线程使用模型之一管道Pipeline]
场景 1.经常在Windows, MacOSX 开发C多线程程序的时候, 经常需要和线程打交道, 如果开发人员的数量不多时, 同时掌握Win32和pthread线程 并不是容易的事情, 而且使用Win ...
- 分享一个关于pthread线程栈在mm_struct里面的分布问题
大家好,本人被下面这个问题困扰了一段时间,最近似乎找到了答案. 这里和大家分享一下,可能对有相同困惑的同学有点帮助,同时也请各位帮忙看看错漏的地方. 1================问题: 在使用p ...
- 【C/C++多线程编程之五】pthread线程深入理解
多线程编程之pthread线程深入理解 Pthread是 POSIX threads 的简称,是POSIX的线程标准. 前几篇博客已经能给你初步的多线程概念.在进一步学 ...
- 【C/C++多线程编程之十】pthread线程私有数据
多线程编程之线程私有数据 Pthread是 POSIX threads 的简称.是POSIX的线程标准. 线程同步从相互排斥量[C/C++多线程编程之六]pthread相互排 ...
- [转]c++多线程编程之pthread线程深入理解
多线程编程之pthread线程深入理解 Pthread是 POSIX threads 的简称,是POSIX的线程标准. 前几篇博客已经能给你初步的多线程概念.在进一 ...
- pthread 线程立即取消的两种方法
1.相关函数介绍 a. int pthread_cancel(pthread_t thread) 1发送终止信号给thread线程,如果成功则返回0,否则为非0值.发送成功并不意味着thread会终止 ...
- C++代码利用pthread线程池与curl批量下载地图瓦片数据
项目需求编写的程序,稳定性有待进一步测试. 适用场景:在网络地图上,比如天地图与谷歌地图,用户用鼠标在地图上拉一个矩形框,希望下载该矩形框内某一层级的瓦片数据,并将所有瓦片拼接成一个完整的,包含地理坐 ...
随机推荐
- ETL开源工具kettle学习笔记
一 Kettle配置与部署 参考1:http://www.cnblogs.com/limengqiang/archive/2013/01/16/KettleApply1.html 1.下载kettle ...
- Java规则引擎及JSR-94[转]
规则引擎简介 Java规则引擎是推理引擎的一种,它起源于基于规则的专家系统. Java规则引擎将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策.Java规则引擎接 ...
- Quest *nix Xwindows
国内一般网站搜到的linux系统添加Xwindows都是无法完成的,至少我在Ct6.3上不行,也许是yum源配置不同问题 我举个站点大家自己上去看,本人就不多说了,多说也无益,. http://yao ...
- 出现The folder is already a source folder
右键build path -> configure build path -> source ,选择 src/main/java.src/test/java删除,然后再新建.
- tree的所有节点都勾选上或者取消勾选
还有一个功能,就是让tree的所有节点都勾选上或者取消勾选,在api中找了一下有一个方法: check target 选中指定节点. 那我们只能是选中根节点后,实现全选. getRoot none 获 ...
- Python的索引迭代
Python中,迭代永远是取出元素本身,而非元素的索引. 对于有序集合,元素确实是有索引的.有的时候,我们确实想在 for 循环中拿到索引,怎么办? 方法是使用 enumerate() 函数: > ...
- mesos in docker
docker pull mesosphere/mesos-master:1.4.0 docker pull mesosphere/mesos-slave:1.4.0 在Docker中运行Mesos的推 ...
- sqlserver for xml
FOR XML子句有四种最基本的模式 1.AUTO模式:返回数据表为起表名的元素,每一列的值返回为属性:2.RAW模式:返回数据行为元素,每一列的值作为元素的属性: 3.PATH模式:通过简单的XPa ...
- JS遍历子孙树
function fn(dataList,parent_id){ var result = [] , temp; for(var i in dataList){ if( ...
- int类型与char类型的转换
---------siwuxie095 Java对char类型的数据在底层是按int类型来处理的 (只是显示出来仍然是字符型) 1.int类型与char ...