一番码客 : 挖掘你关心的亮点。 http://efonfighting.imwork.net
4 - 线程的数据处理5 - 线程的同步和互斥:互斥锁信号量条件变量参考
在单线程的程序里,有两种基本的数据:全局变量和局部变量。但在多线程程序里,还有第三种数据类型:线程数据(TSD: Thread-Specific Data)。
线程数据和全局变量很象,在线程内部,各个函数可以象使用全局变量一样调用它,但它对线程外部的其它线程是不可见的。也就是说,我们要在线程中使用全局变量,但是这个全局变量在各个线程中是独立的。
例如我们常见的变量errno,它返回标准的出错信息。它显然不能是一个局部变量,几乎每个函数都应该可以调用它;但它又不能是一个全局变量,否则在A线程里输出的很可能是B线程的出错信息。
要实现诸如此类的变量,我们就必须使用线程数据。我们为每个线程数据创建一个键,它和这个键相关联,在各个线程里,都使用这个键来指代线程数据,但在不同的线程里,这个键代表的数据是不同的,在同一个线程里,它代表同样的数据内容。
相关的函数和结构:
互斥锁用来保证一段时间内只有一个线程在执行一段代码。一般使用流程:
注意:加锁、解锁之间不能return或break,否则会死锁。
信号量是一种特殊的变量,本质上是一个非负的整数计数器,可以被增加或减少,但系统保证对该变量的访问是原子操作(这能控制多个线程操作同一资源时的顺序问题)。如果一个程序中有多个线程试图改变一个信号量的值,系统将保证所有的操作都将依次进行。
这里需要引入新的头文件semaphore.h
互斥锁是用来给资源上锁的,而条件变量是用来等待而不是用来上锁的。
条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。
通常条件变量和互斥锁同时使用。
和条件变量使用有关的几个重要函数:
/*
初始化与销毁:
条件变量采用的数据类型是pthread_cond_t, 在使用之前必须要进行初始化, 这包括两种方式:
- 静态: 可以把常量PTHREAD_COND_INITIALIZER给静态分配的条件变量.
- 动态: pthread_cond_init函数, 是释放动态条件变量的内存空间之前, 要用pthread_cond_destroy对其进行清理.
*/
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
int pthread_cond_destroy(pthread_cond_t *cond);
/*
等待条件:
等待条件函数等待条件变为真, 传递给pthread_cond_wait的互斥量对条件进行保护, 调用者把锁住的互斥量传递给函数. 函数把调用线程放到等待条件的线程列表上, 然后对互斥量解锁, 这两个操作是原子的. 这样便关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道, 这样线程就不会错过条件的任何变化.
当pthread_cond_wait返回时, 互斥量再次被锁住.
*/
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
/*通知条件:
这两个函数用于通知线程条件已经满足. 调用这两个函数, 也称向线程或条件发送信号.
必须注意, 一定要在改变条件状态以后再给线程发送信号.
*/
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有线程的阻塞
免费知识星球: 一番码客-积累交流 微信公众号:一番码客 微信:Efon-fighting 网站:http://efonfighting.imwork.net