博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C/C++ 多线程机制
阅读量:5890 次
发布时间:2019-06-19

本文共 8491 字,大约阅读时间需要 28 分钟。

一、C/C++多线程操作说明

C/C++多线程基本操作如下: 

1. 线程的建立结束 
2. 线程的互斥和同步 
3. 使用信号量控制线程 
4. 线程的基本属性配置 

在C/C++代码编写时,使用多线程机制,首先需要做的事情就是声明引用,具体如下:

#include "pthread.h"

二、线程基本操作方法

基本线程操作:

1. pthread_create():创建线程开始运行相关线程函数,运行结束则线程退出

2. pthread_eixt():因为exit()是用来结束进程的,所以则需要使用特定结束线程的函数

3. pthread_join():挂起当前线程,用于阻塞式地等待线程结束,如果线程已结束则立即返回,0=成功

4. pthread_cancel():发送终止信号给thread线程,成功返回0,但是成功并不意味着thread会终止

5. pthread_testcancel():在不包含取消点,但是又需要取消点的地方创建一个取消点,以便在一个没有包含取消点的执行代码线程中响应取消请求.

6. pthread_setcancelstate():设置本线程对cancle线程的反应

7. pthread_setcanceltype():设置取消状态 继续运行至下一个取消点再退出或者是立即执行取消动作

8. pthread_setcancel():设置取消状态

三、线程互斥与同步机制 

基本的互斥与同步的操作方法:

1. pthread_mutex_init():互斥锁的初始化

2. pthread_mutex_lock():锁定互斥锁,如果尝试锁定已经被上锁的互斥锁则阻塞至可用为止

3. pthread_mutex_trylock():非阻塞的锁定互斥锁

4. pthread_mutex_unlock():释放互斥锁

5. pthread_mutex_destory():互斥锁销毁函数

四、信号量线程控制机制

C/C++在使用信号量机制的时候,默认的信号量为匿名信号量。

1. sem_init(sem):初始化一个定位在sem的匿名信号量

2. sem_wait():把信号量减1操作,如果信号量的当前值为0则进入阻塞,为原子操作

3. sem_trywait():如果信号量的当前值为0则返回错误而不是阻塞调用(errno=EAGAIN),其实是sem_wait()的非阻塞版本

4. sem_post():给信号量的值加1,它是一个“原子操作”,即同时对同一个信号量做加1,操作的两个线程是不会冲突的

5. sem_getvalue(sval):把sem指向的信号量当前值放置在sval指向的整数上

6. sem_destory(sem):销毁由sem指向的匿名信号量

五、多线程实践

1. 基本的线程及建立运行

下面的代码是C/C++开发的基本的线程的运行,使用的就是最基本的pthread.h:

/* thread.c */#include 
#include
#include
#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 = 0; int count = 0; printf("Thread %d is starting\n", thrd_num); for (count = 0; count < REPEAT_NUMBER; count++) { delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1; 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 = 0, res; void * thrd_ret; srand(time(NULL)); for (no = 0; no < THREAD_NUMBER; no++) { /* 创建多线程 */ res = pthread_create(&thread[no], NULL, thrd_func, (void*)no); if (res != 0) { printf("Create thread %d failed\n", no); exit(res); } } printf("Create treads success\n Waiting for threads to finish...\n"); for (no = 0; 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 0; }

例程中循环3次建立3条线程,并且使用pthread_join函数依次等待线程结束; 

线程中使用rand()获取随机值随机休眠5次,随意会出现后执行的线程先执行完成; 
运行结果:

$ gcc thread.c -lpthread$ ./a.out Create treads success Waiting for threads to finish...Thread 0 is startingThread 1 is startingThread 2 is startingThread 1: job 0 delay = 2Thread 1: job 1 delay = 2Thread 0: job 0 delay = 8Thread 2: job 0 delay = 10Thread 2: job 1 delay = 3Thread 1: job 2 delay = 10Thread 0: job 1 delay = 8Thread 0: job 2 delay = 3Thread 0: job 3 delay = 1Thread 2: job 2 delay = 8Thread 1: job 3 delay = 8Thread 1: job 4 delay = 1Thread 1 finished        Thread 2: job 3 delay = 6        Thread 0: job 4 delay = 7Thread 0 finishedThread 0 joinedThread 1 joined        Thread 2: job 4 delay = 10Thread 2 finishedThread 2 joined

可以看到,线程1先于线程0执行,但是pthread_join的调用时间顺序,先等待线程0执行; 

由于线程1已经早结束,所以线程0被pthread_join等到的时候,线程1已结束,就在等待到线程1时,直接返回; 

2. 线程执行的互斥和同步pthread_mutex_lock

下面我们在上面的程序中增加互斥锁:

/*thread_mutex.c*/#include 
#include
#include
#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 = 0, count = 0; 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 = 0; count < REPEAT_NUMBER; count++) { delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1; 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 = 0, res; void * thrd_ret; srand(time(NULL)); /* 互斥锁初始化 */ pthread_mutex_init(&mutex, NULL); for (no = 0; no < THREAD_NUMBER; no++) { res = pthread_create(&thread[no], NULL, thrd_func, (void*)no); if (res != 0) { printf("Create thread %d failed\n", no); exit(res); } } printf("Create treads success\n Waiting for threads to finish...\n"); for (no = 0; 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 0; }

在上面的例程中直接添加同步锁pthread_mutex_t; 

在线程中加入,于是程序在执行线程程序时; 
调用pthread_mutex_lock上锁,发现上锁时候后进入等待,等待锁再次释放后重新上锁; 
所以线程程序加载到队列中等待,等待成功上锁后继续执行程序代码; 
运行结果如下:

$gcc thread_mutex.c -lpthread$ ./a.out Create treads success Waiting for threads to finish...Thread 0 is starting        Thread 0: job 0 delay = 9        Thread 0: job 1 delay = 4        Thread 0: job 2 delay = 7Thread 0 finishedThread 0 joinedThread 1 is starting        Thread 1: job 0 delay = 6        Thread 1: job 1 delay = 4        Thread 1: job 2 delay = 7Thread 1 finishedThread 1 joinedThread 2 is starting        Thread 2: job 0 delay = 3        Thread 2: job 1 delay = 1        Thread 2: job 2 delay = 6Thread 2 finishedThread 2 joined

 

3. 使用信号量控制线程的执行顺序sem_post

修改上面例程,上面的是使用pthread_mutex_lock互斥锁控制线程执行顺序, 

使用另外一种线程执行顺序的控制:

/* thread_sem.c */#include 
#include
#include
#include
#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 = 0; int count = 0; sem_wait(&sem[thrd_num]); printf("Thread %d is starting\n", thrd_num); for (count = 0; count < REPEAT_NUMBER; count++) { delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1; 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 = 0, res; void * thrd_ret; srand(time(NULL)); for (no = 0; no < THREAD_NUMBER; no++) { sem_init(&sem[no], 0, 0); res = pthread_create(&thread[no], NULL, thrd_func, (void*)no); if (res != 0) { 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 - 1]); for (no = THREAD_NUMBER - 1; no >= 0; 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 - 1) % THREAD_NUMBER]); } for (no = 0; no < THREAD_NUMBER; no++) { sem_destroy(&sem[no]); } return 0; }

 

执行结果,仍然是建立3条线程,每条线程执行时休眠随机时长:

$ gcc thread_sem.c -lpthread $ ./a.out Create treads success Waiting for threads to finish...Thread 2 is starting        Thread 2: job 0 delay = 9        Thread 2: job 1 delay = 9        Thread 2: job 2 delay = 5Thread 2 finishedThread 2 joinedThread 1 is starting        Thread 1: job 0 delay = 5        Thread 1: job 1 delay = 7        Thread 1: job 2 delay = 4Thread 1 finishedThread 1 joinedThread 0 is starting        Thread 0: job 0 delay = 3        Thread 0: job 1 delay = 9        Thread 0: job 2 delay = 8Thread 0 finishedThread 0 joined

执行结果与第2个例程非常相似,只不过教材中进行倒序执行而已; 

那么这种方式其实与使用互斥锁相比,代码量可读性基本持平不相上下;

 

转载地址:http://ezfsx.baihongyu.com/

你可能感兴趣的文章
编译内核出错:invalid option `abi=aapcs-linux' 解决办法
查看>>
System.Func<>与System.Action<>
查看>>
[翻译] EnterTheMatrix
查看>>
asp.net开源CMS推荐
查看>>
我所思考的生活,致半年后的自己
查看>>
Python 学习书籍推荐
查看>>
csharp skype send message in winform
查看>>
jQuery plugin: Tablesorter 2.0
查看>>
csharp:datagridview enter Half Width and Full Width characters
查看>>
MMORPG 游戏服务器端设计--转载
查看>>
C#实现无标题栏窗体点击任务栏图标正常最小化或还原的解决方法
查看>>
[转]GetLastInputInfo计时用户离开电脑及软件在指定时间锁定等
查看>>
Windows 操作系统与 .NET Framework
查看>>
Box2dの自定义多边形
查看>>
HDU 1425 ( sort )
查看>>
Windows Phone 7 框架和页面
查看>>
Directx11教程(31) 纹理映射(1)
查看>>
Android——Button的颜色
查看>>
创建ITS mobile 应用程序步骤
查看>>
《星辰傀儡线》人物续:“灭世者”、“疯狂者”、“叛逆者”三兄妹
查看>>