条件变量pthread_cond_t

#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,thread1,(void *)NULL);/*创建进程t_a*/
    pthread_create(&t_b,NULL,thread2,(void *)NULL); /*创建进程t_b*/
    pthread_join(t_a, NULL);/*等待进程t_a结束*/
    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<=6;i++)
    {
        pthread_mutex_lock(&mutex);/*锁住互斥量*/
        printf("thread1: lock %d\n", __LINE__);
        if(i%3==0){
            printf("thread1:signal 1  %d \n", __LINE__);
            pthread_cond_signal(&cond);/*条件改变,发送信号,通知t_b进程*/
            printf("thread1:signal 2  %d\n", __LINE__);
            sleep(1);
        }
        pthread_mutex_unlock(&mutex);/*解锁互斥量*/
        printf("thread1: unlock %d\n\n", __LINE__);
        sleep(1);
    }
}
void *thread2(void *junk)
{
    while(i<6)
    {
        pthread_mutex_lock(&mutex);
        printf("thread2: lock %d\n", __LINE__);
        if(i%3!=0){
            printf("thread2: wait 1  %d\n", __LINE__);
            pthread_cond_wait(&cond,&mutex);/*解锁mutex,并等待cond改变*/
            printf("thread2: wait 2  %d\n", __LINE__);
        }
        pthread_mutex_unlock(&mutex);
        printf("thread2: unlock %d\n\n", __LINE__);
        sleep(1);
    }
}

[root@panda huang]# gcc 1.c -lpthread -o tcd

[root@panda huang]# ./tcd

thread2: lock 43
thread2: wait 1  45
thread1: lock 26
thread1: unlock 34


thread1: lock 26
thread1: unlock 34


thread1: lock 26
thread1:signal 1  28 
thread1:signal 2  30
thread1: unlock 34


thread2: wait 2  47
thread2: unlock 50


thread2: lock 43
thread2: unlock 50


thread1: lock 26
thread1: unlock 34


thread2: lock 43
thread2: wait 1  45
thread1: lock 26
thread1: unlock 34


thread1: lock 26
thread1:signal 1  28 
thread1:signal 2  30
thread1: unlock 34


thread2: wait 2  47
thread2: unlock 50


展开阅读全文

一个使用pthread_cond_t条件变量的完整示例

03-24

[code=c]rn/*rn * test3.c rn * Copyright 2016 Che Hongwei rn * rn * The MIT License (MIT)rn * rn */rnrn#include rn#include rn#include rn#include rn#include rnrn#define N 6rnrn/* ************************rn * 在使用条件变量时,尽可能地创建一个单独的互斥锁,将其仅用于同步条件变量cond,rn * 假使为了省事,将该mutex用在了其他地方,如果实现的逻辑有出了差错,可能会出现不可预知的结果rn * 为此,下面自定义了一个结构体,将cond和mutex强行捆绑在一起,避免误用rn * */rntypedef struct cond_mutexrnrn pthread_cond_t c;rn pthread_mutex_t m;rncond_mutex_t;rnrn/* ************************rn * 初始化 互斥锁 和 条件变量 rn * */rncond_mutex_t cm = rnrn PTHREAD_COND_INITIALIZER,rn PTHREAD_MUTEX_INITIALIZERrn;rn rn rnstatic void * wait_thread(void * param); // 等待线程rnstatic void * worker_thread(void * param); // 工作者线程rnrn// 用一个mutex来同步对count的操作rnpthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;rnstatic int count = 0;rnstatic int data[N];rnrnunsigned int seed;rnvolatile int quit = 0; // notify threads to quitrnrnint main(int argc, char ** argv)rnrn int rc;rn int i;rn#define NUM_WORKERS (4)rn pthread_t th[NUM_WORKERS + 1]; // 1个等待线程、NUM_WORKERS个工作者线程rn seed = time(NULL);rn rn void * ret_code = NULL;rn rn // 创建等待线程rn rc = pthread_create(&th[0], NULL, wait_thread, NULL);rn if(0 != rc)rn rn perror("pthread_create");rn exit(1);rn rn usleep(5000); // 5 msrn rn // 创建工作者线程rn for(i = 1; i <= NUM_WORKERS; ++i)rn rn rc = pthread_create(&th[i], NULL, worker_thread, NULL);rn if(0 != rc)rn rn perror("pthread_create");rn exit(1);rn rn rn rn char c = 0;rn printf("press enter to quit.\n");rn while(1)rn rn scanf("%c", &c);rn if(c == '\n') break;rn rn rn quit = 1;rn pthread_cond_broadcast(&cm.c); // 激活在所有线程中正在等待中的条件变量rn rn pthread_join(th[0], &ret_code);rn for(i = 1; i <= NUM_WORKERS; ++i)rn rn pthread_join(th[i], &ret_code);rn rn rn rn rc = (int)(long)ret_code;rn rn pthread_mutex_destroy(&mutex);rn pthread_cond_destroy(&cm.c);rn pthread_mutex_destroy(&cm.m);rn return rc; rnrnrnstatic void * worker_thread(void * param)rnrn while(!quit)rn rn pthread_mutex_lock(&mutex); // 先加锁之后,再修改data和count值rn rn if(quit) // 有可能在锁定等待期间被用户强行退出rn rn pthread_mutex_unlock(&mutex);rn break;rn rn if(count == N) //某一个【工作者线程】已经触发了条件变量,但【等待线程】还没来得及加锁rn rn printf("正在与【等待线程】争抢资源...\n"); rn pthread_mutex_unlock(&mutex); rn usleep(10000); // sleep 10 ms, 给其他线程一个机会rn continue;rn rn //~ #ifdef _DEBUGrn if(count > N) // 应该不可能发生,仅供调试时使用rn rn fprintf(stderr, "同步的逻辑出现问题,请检查源代码。\n");rn printf("请按回车建退出...\n");rn quit = 1;rn pthread_mutex_unlock(&mutex);rn break;rn rn //~ #endifrn rn data[count++] = rand_r(&seed) % 1000; rn rn if(count == N)rn rn pthread_mutex_lock(&cm.m); rn pthread_cond_signal(&cm.c);rn pthread_mutex_unlock(&cm.m); rn rn pthread_mutex_unlock(&mutex); // 解锁rn usleep(100000); // 100 ms; 人为故意地延迟一下,模拟一下真实场景可能需要的工作量。rn rn pthread_exit((void *)(long)0);rnrnrnstatic void * wait_thread(void * param)rnrn int i, sum;rn pthread_mutex_lock(&cm.m); rn while(!quit)rn rn pthread_cond_wait(&cm.c, &cm.m);rn if(quit) break; //有可能是在等待期间被用户干预,强制退出的(在while中判断时quit可能还是0)rn rn pthread_mutex_lock(&mutex); // 先上锁,避免其他线程修改 data 和 count 值rn sum = 0;rn printf("average = (");rn for(i = 0; i < N; ++i)rn rn sum += data[i];rn printf(" %3d ", data[i]);rn if(i < (N - 1)) printf("+");rn rn rn rn printf(") / %d = %.2f\n", N, (double)sum / (double)N);rn count = 0;rn pthread_mutex_unlock(&mutex);rn rn // end whilern rn pthread_mutex_unlock(&cm.m);rn rn pthread_exit((void *)(long)0);rnrnrn[/code]rnrn=======================================rn[b]简要说明[/b]rnrn条件变量的作用是,仅当某个特定值满足某个条件时才执行后续的操作。rnrn考虑下面这种情况:假设在线程1中,只有当(count > N) 时才需要执行后续操作,但这个count值是由其他线程(可能有多个)修改的,本线程并不知道什么时候才能满足条件。rn如果需要后续的操作能及时响应,假使不使用条件变量,那么需要在一个循环中不断检测count值,这将极大的消耗CPU资源;但如果用sleep等待,有可能会导致后续操作延误,而使任务无法及时完成。rnrn为了解决上面这种问题,于是引入了条件变量,在线程1中用下面这种方式来等待:rnpthread_cond_wait(&cond, &mutex);rn只要不满足预定的条件,那么上面这行将一直保持阻塞状态,不会占用任何CPU资源。rnrn================rn其他线程:rn当操作count值的另外某个线程执行到另count = N时,rn1. 先给mutex加锁,用于保护cond变量,确保不会有其他线程重复触发条件激活的信号rnpthread_mutex_lock(&mutex);rn2. 发个信号,告知条件就绪rnpthread_cond_signal(&cond); // 此时,pthread_cond_wait会激活,线程1开始支持后续操作rn3. 解锁rnpthread_mutex_lock(&mutex);rn-----------------------rnrn线程1:rn当pthread_cond_wait执行时,在该函数内部会执行如下的原子操作:rn检查cond状态,rna. 如果cond出于阻塞状态,先解锁mutex,并将该线程挂起在后台;rnb. 如果cond激活,那么就加锁mutex,并完成此次等待操作,允许执行线程1后续的工作。rnrn具体流程是:rn[code=c]rn// 必须先加锁,才能执行pthread_cond_wait,否则会出现不可预知的结果rnpthread_mutex_lock(&mutex); rn rnwhile(1) // 如果需要反复执行rnrn pthread_cond_wait(&cond, &mutex); // 该行执行后,若cond为阻塞状态,则mutex将解锁rn // 由于(b)步骤的操作,mutex此时出于加锁状态rn // do some workrn rn // finish workrn if (满足某个终止条件)break;rn // 由于是个循环,此时会返回到pthread_cond_wait行,注意此时mutex还是加锁状态rnrnpthread_mutex_unlock(&mutex); // 如果因为某些原因直接跳出了循环,需要解开被pthread_cond_wait加的锁rn[/code]rn======================================rnrn在使用条件变量时有个注意事项,即必须确保线程1中的 pthread_cond_wait已经执行了之后,才能在其他线程中执行pthread_cond_sig操作,否则会出现不可预知的结果(我以前曾遇到过这种情况,找了很久才发现原因)。rn可以在用pthread_create创建了线程1后。先 usleep几毫秒,然后在创建其他工作线程,这样可以确保取得预期的效果。rn 论坛

没有更多推荐了,返回首页