à背景知识介绍
1 互斥量
互斥量函数有
pthread_mutex_init 初始化一个互斥量
pthread_mutex_lock 给一个互斥量加锁
pthread_mutex_trylock 加锁,如果失败不阻塞
pthread_mutex_unlock 解锁
互斥量从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。
2 条件变量
静态方式使用PTHREAD_COND_INITIALIZER常量,如下:
pthread_cond_t cond=PTHREAD_COND_INITIALIZER
动态方式调用pthread_cond_init()函数,API定义如下:
pthread_cond_init
pthread_cond_wait无条件等待
ipthread_cond_timedwait 计时等待
pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个
而pthread_cond_broadcast()则激活所有等待线程。
条件变量实现的是一种通知机制,先在线程B中调用pthread_cond_wait(cond,mutex)等待条件变量被触发而且在没有被激发之前B就一直阻塞在pthread_cond_wait,一旦在线程A中调用pthread_cond_signal()从而激发条件变量,即通知线程B条件变量可用则B中中pthread_cond_wait由阻塞变成执行状态(执行过程中mutex首先unlock->wait return->mutexlock )。
à互斥量和条件变量之间的关系
1 为了保证 线程A对条件变量可用的通知发出,线程B接收该通知的过程做到顺序化。保证前一时刻有一个已经发出的条件变量可用通知之后,才让B阻塞于pthread_cond_wait(为了实现这个,互斥量是个不错的选择)。
2如果没有互斥量可能造成 thread_func访问临界资源时,main()也去访问造成竞争。
à贴一个例子:
#include <pthread.h>
#include <unistd.h>
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
struct node {
int n_number;
struct node *n_next;
} *head = NULL;
/*[thread_func]*/
static void cleanup_handler(void *arg)
{
printf("Cleanup handler of second thread./n");
free(arg);
(void)pthread_mutex_unlock(&mtx);
}
static void *thread_func(void *arg)
{
struct node *p = NULL;
pthread_cleanup_push(cleanup_handler, p);
while (1) {
pthread_mutex_lock(&mtx);
while (head == NULL) { //这个while要特别说明一下,单个pthread_cond_wait功能很完善,为何这里要有一个while (head == NULL)呢?因为pthread_cond_wait里的线程可能会被意外唤醒,如果这个时候head != NULL,则不是我们想要的情况。这个时候,应该让线程继续进入pthread_cond_wait
pthread_cond_wait(&cond, &mtx); // pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);,再读取资源
//用这个流程是比较清楚的/*block-->unlock-->wait() return-->lock*/
}
p = head;
head = head->n_next;
printf("Got %d from front of queue/n", p->n_number);
free(p);
pthread_mutex_unlock(&mtx); //临界区数据操作完毕,释放互斥锁
}
pthread_cleanup_pop(0);
return 0;
}
int main(void)
{
pthread_t tid;
int i;
struct node *p;
pthread_create(&tid, NULL, thread_func, NULL);
/*[tx6-main]*/
for (i = 0; i < 10; i++) {
p = malloc(sizeof(struct node));
p->n_number = i;
pthread_mutex_lock(&mtx); //需要操作head这个临界资源,先加锁,
p->n_next = head;
head = p;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx); //解锁
sleep(1);
}
printf("thread 1 wanna end the line.So cancel thread 2./n");
pthread_cancel(tid); //关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,子线程会在最近的取消点,退出线程,而在我们的代码里,最近的取消点肯定就是pthread_cond_wait()了。关于取消点的信息,有兴趣可以google,这里不多说了
pthread_join(tid, NULL);
printf("All done -- exiting/n");
return 0;
}
http://blog.youkuaiyun.com/hairetz/article/details/4535920