Linux系统编程—线程—线程条件控制实现线程的同步

Posted 是光哥呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux系统编程—线程—线程条件控制实现线程的同步相关的知识,希望对你有一定的参考价值。

Linux下C编程的条件变量
条件变量是线程中的东西,就是等待某一条件的发生,和信号一样。

条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等待另一个线程发送信号来弥补互斥锁的不足,所以互斥锁和条件变量通常一起使用。

当条件满足的时候,线程通常解锁并等待该条件发生变化,一旦另一个线程修改了环境变量,就会通知相应的环境变量唤醒一个或者多个被这个条件变量阻塞的线程。这些被唤醒的线程将重新上锁,并测试条件是否满足。一般来说条件变量被用于线程间的同步;当条件不满足的时候,允许其中的一个执行流挂起和等待

步骤:
1. 创建条件变量
先全局定义一个pthread_cond_t类型

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。

2. 等待

1条件等待

int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex);

2时间等待

int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);

等待条件有两种方式:条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEDOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。

无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。阻塞时处于解锁状态。

3. 触发

int pthread_cond_signal(pthread_cond_t cond);
int pthread_cond_broadcast(pthread_cond_t cond);
// 返回:若成功返回0,否则返回错误编号

这两个函数可以用于通知线程条件已经满足。pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast函数将唤醒等待该条件的所有进程。注意一定要在改变条件状态以后再给线程发信号。

4、销毁条件变量

int pthread_cond_destroy(pthread_cond_t cond);
// 返回:若成功返回0,否则返回错误编号

==================================================
场景:
fun1检测等待pthread_cond_wait
fun2计数到达3时使用pthread_cond_signal触发退出动作

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>

pthread_mutex_t m;
pthread_cond_t cond;
int g_data=0;

void *func1(void *arg)
{
        printf("t1:%ld thread is create\\n",(unsigned long)pthread_self());
        printf("t1:param is %d\\n",*((int *)arg));
        while(1){
                pthread_cond_wait(&cond,&m);
                printf("t1:run============\\n");
                printf("t1:%d\\n",g_data);
                g_data=0;
                sleep(1);
        }
}

void *func2(void *arg)
{
        printf("t2:%ld thread is create\\n",(unsigned long)pthread_self());
        printf("t2:param is %d\\n",*((int *)arg));

        static int cnt=0;

        while(1){
                printf("t2:%d\\n",g_data);
                pthread_mutex_lock(&m);
                g_data++;
                if(g_data==3){
                        pthread_cond_signal(&cond);
                }
                pthread_mutex_unlock(&m);
                sleep(1);
                if(cnt++==10){
                exit(1);
                }
        }
}

int main()
{
        int ret;
        int param=100;

        pthread_t t1;
        pthread_t t2;
        pthread_mutex_init(&m,NULL);
        pthread_cond_init(&cond,NULL);

        ret=pthread_create(&t1,NULL,func1,(void *)&param);
        ret=pthread_create(&t2,NULL,func2,(void *)&param);

        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        pthread_mutex_destroy(&m);
        pthread_cond_destroy(&cond);
        return 0;
}

运行一次的效果如下图所示:
在这里插入图片描述

====================================================
编写个测试程序,可根据需要运行多次代码

#include <stdlib.h>

int main(int argc,char **argv)
{
        int time=atoi(argv[1]);
        int i=0;
        for(i=0;i<time;i++){
        system("./demo7");
        }
}

在这里插入图片描述
编译测试程序后输入./a.out 10 >>test.ret.txt &
10是运行十次的意思 &是后台运行
运行完后,打开test.ret.txt可以看到10次运行效果都写入到文件里了

在这里插入图片描述

以上是关于Linux系统编程—线程—线程条件控制实现线程的同步的主要内容,如果未能解决你的问题,请参考以下文章

Linux多线程编程与同步实例(基于条件变量)

Linux系统编程 多线程

Linux系统编程 多线程

Linux系统编程-(pthread)线程通信(条件变量)

Linux C编程之二十二 Linux线程池实现

linux下多线程编程