Linux 多线程同步问题 条件变量
来源:互联网 发布:mac 双系统 默认启动 编辑:程序博客网 时间:2024/04/29 06:48
互斥锁:用来上锁。
条件变量:用来等待,当条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
函数介绍:
1.
名称:
pthread_cond_init
目标:
条件变量初始化
头文件:
#include < pthread.h>
函数原形:
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
参数:
cptr 条件变量
attr 条件变量属性
返回值:
成功返回0,出错返回错误编号。
pthread_cond_init函数可以用来初始化一个条件变量。他使用变量attr所指定的属性来初始化一个条件变量,如果参数attr为空,那么它将使用缺省的属性来设置所指定的条件变量。
2.
名称:
pthread_cond_destroy
目标:
条件变量摧毁
头文件:
#include < pthread.h>
函数原形:
int pthread_cond_destroy(pthread_cond_t *cond);
参数:
cptr 条件变量
返回值:
成功返回0,出错返回错误编号。
pthread_cond_destroy函数可以用来摧毁所指定的条件变量,同时将会释放所给它分配的资源。调用该函数的进程也并不要求等待在参数所指定的条件变量上。
3.
名称:
pthread_cond_wait/pthread_cond_timedwait
目标:
条件变量等待
头文件:
#include < pthread.h>
函数原形:
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t mytex,const struct timespec *abstime);
参数:
cond 条件变量
mutex 互斥锁
返回值:
成功返回0,出错返回错误编号。
第一个参数*cond是指向一个条件变量的指针。第二个参数*mutex则是对相关的互斥锁的指针。函数pthread_cond_timedwait函数类型与函数pthread_cond_wait,区别在于,如果达到或是超过所引用的参数*abstime,它将结束并返回错误ETIME.pthread_cond_timedwait函数的参数*abstime指向一个timespec结构。该结构如下:
typedef struct timespec{
time_t tv_sec;
long tv_nsex;
}timespec_t;
3.
名称:
pthread_cond_signal/pthread_cond_broadcast
目标:
条件变量通知
头文件:
#include < pthread.h>
函数原形:
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
参数:
cond 条件变量
返回值:
成功返回0,出错返回错误编号。
参数*cond是对类型为pthread_cond_t 的一个条件变量的指针。当调用pthread_cond_signal时一个在相同条件变量上阻塞的线程将被解锁。如果同时有多个线程阻塞,则由调度策略确定接收通知的线程。如果调用pthread_cond_broadcast,则将通知阻塞在这个条件变量上的所有线程。一旦被唤醒,线程仍然会要求互斥锁。如果当前没有线程等待通知,则上面两种调用实际上成为一个空操作。如果参数*cond指向非法地址,则返回值EINVAL。
下面是一个简单的例子,我们可以从程序的运行来了解条件变量的作用。
#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);
}
}
程序创建了2个新线程使他们同步运行,实现进程t_b打印20以内3的倍数,t_a打印其他的数,程序开始线程t_b不满足条件等待,线程t_a运行使a循环加1并打印。直到i为3的倍数时,线程t_a发送信号通知进程t_b,这时t_b满足条件,打印i值。
下面是运行结果:
#cc –lpthread –o cond cond.c
#./cond
thread1:1
thread1:2
thread2:3
thread1:4
thread1:5
thread2:6
thread1:7
thread1:8
thread2:9
备注:
pthread_cond_wait 执行的流程首先将这个mutex解锁, 然后等待条件变量被唤醒, 如果没有被唤醒, 该线程将一直休眠, 也就是说, 该线程将一直阻塞在这个pthread_cond_wait调用中, 而当此线程被唤醒时, 将自动将这个mutex加锁,然后再进行条件变量判断(原因是“惊群效应”,如果是多个线程都在等待这个条件,而同时只能有一个线程进行处理,此时就必须要再次条件判断,以使只有一个线程进入临界区处理。),如果满足,则线程继续执行,最后解锁,
也就是说pthread_cond_wait实际上可以看作是以下几个动作的合体:
解锁线程锁
等待线程唤醒,并且条件为true
加锁线程锁.
pthread_cond_signal仅仅负责唤醒正在阻塞在同一条件变量上的一个线程,如果存在多个线程,系统自动根据调度策略决定唤醒其中的一个线程,在多处理器上,该函数是可能同时唤醒多个线程,同时该函数与锁操作无关,解锁是由pthread_mutex_unlock(&mutex)完成
唤醒丢失问题
在线程并没有阻塞在条件变量上时,调用pthread_cond_signal或pthread_cond_broadcast函数可能会引起唤醒丢失问题。
唤醒丢失往往会在下面的情况下发生:
一个线程调用pthread_cond_signal或pthread_cond_broadcast函数;
另一个线程正处在测试条件变量和调用pthread_cond_wait函数之间;
没有线程正在处在阻塞等待的状态下。
- Linux 多线程同步问题 条件变量
- 【Linux多线程同步】条件变量
- Linux多线程同步之条件变量
- 多线程同步条件变量
- 多线程同步条件变量
- 多线程同步条件变量
- linux同步-条件变量
- linux 条件变量--同步
- 多线程同步问题(1)互斥锁和条件变量
- Linux多线程编程入门-同步机制-条件变量
- Linux多线程编程之同步对象编程:条件变量
- Linux多线程基础学习(五)线程同步-条件变量
- linux多线程-----同步机制(互斥量、读写锁、条件变量)
- Linux多线程同步之互斥量和条件变量
- Linux多线程编程(二)线程同步之条件变量
- Linux下多线程同步方式之互斥量,信号量,条件变量
- linux 多线程-条件变量
- Linux 线程同步---条件变量
- 一般看不见的机械原理
- bzoj 1616(dp)
- 如何解决程序/C++Dll的兼容性问题
- Artoolkit的例子simpleVRML详解
- C# Brush的使用
- Linux 多线程同步问题 条件变量
- C# 双缓冲技术实现和高效率的绘图方式
- JS中生成和解析JSON
- 处理java错误”编码 GBK 的不可映射字符“
- 【Maven】依赖机制(四)
- Linux进程间通信——信号量
- 将文件内容先替换后复制2
- POJ 3046 Ant Counting 题解- 多重集组合数问题(附测试数据)
- JDBC学习笔记—数据库连接池(DBCP和C3P0)