目录
☋☋☋ 文章说明:
多线程开发的最基本概念主要包含三点:线程,互斥锁,条件。其中,线程操作又分线程的创建,退出,等待 3 种(http://t.csdn.cn/02KL5)。互斥锁则包括 4 种操作,分别是创建,销毁,加锁和解锁(http://t.csdn.cn/aVEhx)。条件操作有 5 种操作:创建,销毁,触发,广播和等待(此篇)。其他的一些线程扩展概念,如信号灯等,都可以通过上面的三个基本元素的基本操作封装出来。详细请见下表:
一 条件控制说明:
● 条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。
● 条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量,其他线程在获得互斥量之前不会察觉到这种改变,因为必须锁定互斥量以后才能计算条件。
● 条件变量使用之前必须首先初始化,pthread_cond_t数据类型代表的条件变量可以用两种方式进行初始化,可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,但是如果条件变量是动态分配的,可以使用pthread_cond_destroy函数对条件变量进行去除初始化(deinitialize)。
二 线程同步说明:
含义:在保证数据安全(加锁)的情况下,让多个执行流按特定顺序访问临界区的资源,就是线程同步。因为互斥锁虽然能保证线程数据不出错,但是不能保证各线程的执行顺序,所以就需要线程同步。
注意:●如果条件不满足,则需要等待并且释放锁。比如线程A发现线程B没有对数据进行修改,所以他就要等待线程B修改数据;
●要有通知机制。比如线程B把数据修改了,要通知线程A。
三 实现线程同步:条件变量的API
☆ 在使用条件变量API之前需要定义cond的变量类型,如:pthread_cond_t cond;
1. 创建及销毁条件变量
#include <pthread.h> int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t cond); // 返回:若成功返回0,否则返回错误编号
除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。
2. 等待
#include <pthread.h> int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout); // 返回:若成功返回0,否则返回错误编号
● pthread_cond_wait等待条件变为真。如果在给定的时间内条件不能满足,那么会生成一个代表一个出错码的返回变量。传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的互斥量传给函数。函数把调用线程放到等待条件的线程列表上,然后对互斥量解锁,这两个操作都是原子操作。这样就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。pthread_cond_wait返回时,互斥量再次被锁住。
● pthread_cond_timedwait函数的工作方式与pthread_cond_wait函数类似,只是多了一个timeout。timeout指定了等待的时间,它是通过timespec结构指定。
3. 触发
#include <pthread.h> int pthread_cond_signal(pthread_cond_t cond); int pthread_cond_broadcast(pthread_cond_t cond); // 返回:若成功返回0,否则返回错误编号
● 这两个函数可以用于通知线程条件已经满足。pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast函数将唤醒等待该条件的所有进程。
● 注意一定要在改变条件状态以后再给线程发信号。
四 代码实现:
代码说明:
#include <pthread.h>
#include <stdio.h>
int i;
pthread_mutex_t mutex;
pthread_cond_t cond;//定义条件变量
void *func1(void *arg1)
{
pthread_cond_wait(&cond,&mutex);//线程1先等待,等线程2 执行完毕后发出执行信号
for(i=0;i<5;i++){
printf("tid1:%lu\n",pthread_self());
}
}
void *func2(void *arg2)
{
pthread_mutex_lock(&mutex);
for(i=0;i<5;i++){
printf("tid2:%lu\n",pthread_self());
}
printf("===============================\n");
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);//线程2执行完毕后,发出信号让线程1执行
}
int main(void)
{
pthread_t tid1;
pthread_t tid2;
pthread_cond_init(&cond,NULL);//初始化条件变量
pthread_mutex_init(&mutex,NULL);
int ret1 = pthread_create(&tid1,NULL,func1,NULL);
if(ret1 == 0){
printf("main1:creat thread1 success!\n");
}
int ret2 = pthread_create(&tid2,NULL,func2,NULL);
if(ret2 == 0){
printf("main2:creat thread2 success!\n");
}
printf("===============================\n");
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);//销毁条件变量
return 0;
}
dhw@dhw-virtual-machine:~/thread$ ./a.out
main1:creat thread1 success!
main2:creat thread2 success!
===============================
tid2:140681707394624
tid2:140681707394624
tid2:140681707394624 //发送信号。因为线程1等待,所以线程2先执行
tid2:140681707394624
tid2:140681707394624
===============================
tid1:140681715787328
tid1:140681715787328
tid1:140681715787328 //等带接收信号。线程1先等待,等待线程2执行完后收到信号
tid1:140681715787328
tid1:140681715787328