从零学习多线程第三篇--互斥量与条件变量的应用
2014-08-24 13:16
141 查看
条件变量
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。
条件变量的创建与注销
条件变量的创建也是有两种方式:静态方式与动态方式。条件变量的数据结构如下:
typedef union { struct { int __lock; unsigned int __futex; __extension__ unsigned long long int __total_seq; __extension__ unsigned long long int __wakeup_seq; __extension__ unsigned long long int __woken_seq; void *__mutex; unsigned int __nwaiters; unsigned int __broadcast_seq; } __data; char __size[__SIZEOF_PTHREAD_COND_T]; __extension__ long long int __align; } pthread_cond_t;
静态方式:与互斥量一样也存在默认条件变量PTHREAD_COND_INITIALIZER 常量
pthread_cond_t cond=PTHREAD_COND_INITIALIZER
动态方式:通过调用API函数pthread_cond_init函数,函数原型如下
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)创建成功会返回0,失败则返回错误代码。尽管 POSIX 标准中为条件变量定义了属性,但在 LinuxThreads 中没有实现,因此 cond_attr
值通常为 NULL,且被忽略。
线程注销:API函数原型如下
int pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_destroy函数可以用来摧毁所指定的条件变量,同时将会释放所给它分配的资源。调用该函数的进程也并不要求等待在参数所指定的条件变量上。因为
Linux 实现的条件变量没有分配什么资源,所以注销动作只包括检查是否有等待线程。
线程的等待与激活
线程等待API提供了两个API函数int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)注释:前两个参数分别是指向条件变量的指针和指向互斥量的指针,第二个函数的第三个变量是指向timespec结构体的指针,意思是为等待的线程提供倒计时,若时间到了还未被唤醒则返回ETIMEOUT,结束等待。结构体的定义如下
struct timespec { __time_t tv_sec; /* Seconds. */ long int tv_nsec; /* Nanoseconds. */ };
无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求 pthread_cond_wait()(或 pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。mutex 互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP)且在调用 pthread_cond_wait()前必须由本线程加锁pthread_mutex_lock()
,而在更新条件等待队列以前,mutex 保持锁定状态,并在线程挂起进入等待前解锁。
线程的激活
/* Wake up one thread waiting for condition variable COND. */ extern int pthread_cond_signal (pthread_cond_t *__cond) __THROWNL __nonnull ((1)); /* Wake up all threads waiting for condition variables COND. */ extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROWNL __nonnull ((1));注释:二者区别在于第一个只会一次唤醒一个线程但是第二个会唤醒所有等待线程。
3. 其他
pthread_cond_wait()和 pthread_cond_timedwait()都被实现为取消点,因此,在该处等待的线程将立即重 新运行,在重新锁定 mutex 后离开 pthread_cond_wait(),然后执行取消动作。也就是说如果 pthread_cond_wait()被 取消,mutex 是保持锁定状态的,因而需要定义退出回调函数来为其解锁。
条件变量与互斥量例子解析
#include <pthread.h> #include <stdio.h> #include <stdlib.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥锁*/ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;/*初始化条件变量*/ void *thread1(void *); void *thread2(void *); int i=1; int main(void) { pthread_t t_a; pthread_t t_b; pthread_create(&t_a,NULL,thread2,(void *)NULL);/*创建进程t_a*/ pthread_create(&t_b,NULL,thread1,(void *)NULL); /*创建进程t_b*/ pthread_join(t_b, NULL);/*等待进程t_b结束*/ pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); exit(0); } void *thread1(void *junk) { for(i=1;i<=9;i++) { pthread_mutex_lock(&mutex);/*锁住互斥量*/ if(i%3==0) pthread_cond_signal(&cond);/*条件改变,发送信号,通知t_b进程*/ else printf("thead1:%d\n",i); pthread_mutex_unlock(&mutex);/*解锁互斥量*/ sleep(1); } } void *thread2(void *junk) { while(i<9) { pthread_mutex_lock(&mutex); if(i%3!=0) pthread_cond_wait(&cond,&mutex);/*等待*/ printf("thread2:%d\n",i); pthread_mutex_unlock(&mutex); sleep(1); } }
注释:主线程在运行到pthread_jion时被挂起直到子线程运行结束,子线程t_b运行但是只有遇到数字等于3的倍数时才会输出,所以第一次在遇到全局变量i不等于3倍数时使用
使用pthread_cond_wat使其阻塞,线程t_a继续运行,如此循环输出直到子线程运行结束实现线程的同步!
运行结果截图
相关文章推荐
- 多线程中互斥量与条件变量的使用
- 黑马程序员________多线程的理论及应用学习笔记
- 自己学习android网络应用部分,练习的一个多线程的服务器和客户端
- Python 多线程学习05 条件变量 Condition
- Java多线程与并发库高级应用 学习笔记 16-22课 +面试题
- 多线程开发学习笔记之线程同步——互斥量
- 多线程的学习2(小应用)
- C++11学习笔记-----互斥量以及条件变量的使用
- 【黑马程序员】Java多线程学习及应用
- linux c++多线程 线程私有数据 互斥量 条件变量 信号量 读写锁 自旋锁 屏障
- Java多线程的学习和应用
- Android应用开发学习笔记之多线程与Handler消息处理机制
- Android应用开发学习笔记之多线程与Handler消息处理机制
- 从零学习linux多线程---互斥量
- Java多线程学习与Java多线程的简单应用
- 黑马程序员_第三篇:关于多线程的学习
- 多线程编程技术在android系统中的应用,学习多线程不可多得的技术资料
- [多线程学习笔记]互斥量
- Java多线程与并发库高级应用 学习笔记 10-16课
- Qt学习之《C++ GUI Qt4编程》(第14章)多线程互斥量使用错误