首页 > 其他分享 >线程条件变量pthread_cond_t和线程条件锁详解

线程条件变量pthread_cond_t和线程条件锁详解

时间:2023-05-22 19:06:17浏览次数:41  
标签:pthread counter cond printf 线程 NULL


线程条件变量pthread_cond_t和线程条件锁详解

参考文章

条件变量常与互斥锁同时使用,达到线程同步的目的:条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足。

APUE上,关于条件锁。其中有2条总结:

1.使用条件锁前必须先锁住对应的互斥锁。

2.条件锁进入阻塞(pthread_cond_wait)时自动解开对应互斥锁,而一旦跳出阻塞立即再次取得互斥锁,而这两个操作都是原子操作。

示例代码如下:

//互斥锁
pthread_mutex_t counter_lock;
//条件变量 
pthread_cond_t counter_nonzero;
int counter = 0;

void decrement_counter(void *argv)
{
    pthread_mutex_lock(&counter_lock);
    printf("thd1 decrement get the lock \n");
    while(counter == 0)
    {
        printf("thd1 decrement before cond_wait\n");
        pthread_cond_wait(&counter_nonzero, &counter_lock);
        /*
        运行到此处条件锁会自动以原子操作的方式将互斥锁解锁
        条件锁在收到pthread_cond_signal发出的信号后会尝试再次获取到互斥锁由于互斥锁已经被increment_counter函数持有
        因此decrement_counter函数所在的线程进入休眠状态等待increment_counter函数所在的线程解锁互斥锁
        当increment_counter函数所在的线程解锁互斥锁后decrement_counter函数所在的线程从休眠状态恢复开始运行
        */
        printf("thd1 decrement after cond_wait \n");
    }
    counter--;
    printf("thd1 decrement:counter = %d \n", counter);
    pthread_mutex_unlock(&counter_lock);
}

void increment_counter(void *argv)
{
    pthread_mutex_lock(&counter_lock);
    printf("thd2 increment get the lock\n");
    if(counter == 0)
    {
        printf("thd2 increment before cond_signal\n");
        pthread_cond_signal(&counter_nonzero);//发出条件变量信号
        printf("thd2 increment after  cond_signal\n");
    }
    counter++;
    printf("thd2 increment:counter = %d \n", counter);
    pthread_mutex_unlock(&counter_lock);
}

void test_pthread_cond(){
    printf("counter: %d\n", counter);
    pthread_t thd1, thd2;

    pthread_mutex_init(&counter_lock, NULL);
    pthread_cond_init(&counter_nonzero, NULL);

    int ret;
    printf("main1: before creating thd1 decrement \n");
    ret = pthread_create(&thd1, NULL, (void *)decrement_counter, NULL);//先创建的是等待线程,用pthread_cond_wait
    if(ret){
        perror("del:/n");
        return ;
    }
    printf("main2:thd1 is created, begin create thd2 increment \n");
    ret = pthread_create(&thd2, NULL, (void *)increment_counter, NULL);//后创建的是激活线程,用pthread_cond_signal
    if(ret){
        perror("inc: /n");
        return ;
    }
    printf("main3:after thd1 and thd2, begin sleep and exit!\n");
    sleep(3);
    return ;
}

/*
运行结果:
counter: 0
main1: before creating thd1 decrement 
main2:thd1 is created, begin create thd2 increment 
main3:after thd1 and thd2, begin sleep and exit!
thd1 decrement get the lock 
thd1 decrement before cond_wait
thd2 increment get the lock
thd2 increment before cond_signal
thd2 increment after  cond_signal
thd2 increment:counter = 1 
thd1 decrement after cond_wait 
thd1 decrement:counter = 0
*/
//互斥锁
pthread_mutex_t mutex;
//条件变量
pthread_cond_t cond_l;
int i = 1;

void* run(void *s)
{
    pthread_mutex_lock(&mutex);
    while(i == 1)
    {
        printf("线程%u进入等待状态\n", (unsigned int)pthread_self());
        pthread_cond_wait(&cond_l, &mutex);
    }
    printf("已经解开%u\n", (unsigned int)pthread_self());
    pthread_mutex_unlock(&mutex);
    i = 1;

    return ((void *) 1);
}

void testRun(){
    pthread_t pid1;
    pthread_t pid2;
    pthread_t pid3;
    pthread_t pid4;

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond_l, NULL);

    pthread_create(&pid1, NULL, run, NULL );
    printf("new thread:%u\n", (unsigned int)pid1);
    sleep(1);

    pthread_create(&pid2, NULL, run, NULL );
    printf("new thread:%u\n", (unsigned int)pid2);
    sleep(1);

    pthread_create(&pid3, NULL, run, NULL );
    printf("new thread:%u\n", (unsigned int)pid3);
    sleep(1);

    pthread_create(&pid4, NULL, run, NULL );
    printf("new thread:%u\n", (unsigned int)pid4);
    sleep(1);

#if 0
    //不注释
    pthread_mutex_lock(&mutex);
    /*
     new thread:3289088
     线程3289088进入等待状态
     new thread:3825664
     线程3825664进入等待状态
     new thread:4362240
     线程4362240进入等待状态
     new thread:4898816
     线程4898816进入等待状态
     release signal
     release signal
     */
#endif

#if 1
    //注释掉
    //pthread_mutex_lock(&mutex);
    /*
     new thread:3289088
     线程3289088进入等待状态
     new thread:3825664
     线程3825664进入等待状态
     new thread:4362240
     线程4362240进入等待状态
     new thread:4898816
     线程4898816进入等待状态
     release signal
     已经解开3289088
     release signal
     已经解开3825664
     */
#endif

    //pthread_cond_signal每次只会唤醒一个条件锁,唤醒的顺序跟阻塞在条件锁的顺序相同

    i = 2;
    pthread_cond_signal(&cond_l);
    printf("release signal\n");
    sleep(1);

    i = 2;
    pthread_cond_signal(&cond_l);
    printf("release signal\n");
    sleep(1);

    //pthread_join()的作用可以这样理解:主线程等待子线程的终止。
    //也就是在子线程调用了pthread_join()方法后面的代码,只有等到子线程结束了才能执行。
    pthread_join(pid1, NULL );
    pthread_join(pid2, NULL );
    pthread_join(pid3, NULL );
    pthread_join(pid4, NULL );
}


标签:pthread,counter,cond,printf,线程,NULL
From: https://blog.51cto.com/u_16124099/6326570

相关文章

  • springboot添加@Scheduled定时任务多线程执行
    packagecom.example.demo;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.EnableAutoConfiguration;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.autoc......
  • jmeter-线程组之间通信
    方式一:使用插件官方介绍jp@gc-Inter-ThreadCommunicationPostProcessorjp@gc-Inter-ThreadCommunicationPreProcessor......
  • 线程池
    线程池:JDK的线程池有:ThreadPoolExecutor,ScheduledThreadPoolExecutor(带任务调度)ThreadPoolExecutor构造方法参数说明:ThreadPoolExecutor(核心线程数,最大线程数,救急线程存活时间,存活时间单位,阻塞队列),救急线程数=最大线程数-核心线程数,当任务数多于线程数时,如果有救急......
  • < Python全景系列-5 > 解锁Python并发编程:多线程和多进程的神秘面纱揭晓
    欢迎来到我们的系列博客《Python全景系列》!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法。无论你是编程新手,还是有一定基础的开发者,这个系列都将提供你需要的知识和技能。这是本系列的第五篇,我们将深入探讨Python中的......
  • 多线程-sychronized锁膨胀
    sychronized什么是cascas的定义:在操作系统中,CAS通常代表“CompareAndSwap”,它是一种原子操作,用于解决并发访问的问题。具体地说,CAS操作会比较并交换一个内存位置的值,只有当内存位置的值与期望的值相等时,才会将新值写入该位置。如果内存位置的值与期望的值不相等,则说明这个内存位......
  • python的守护线程(简介、作用及代码实例)
    转载:(14条消息)python的守护线程(简介、作用及代码实例)_python守护线程的作用_HXH.py的博客-CSDN博客python守护线程简介守护线程的理解:如果当前python线程是守护线程,那么意味着这个线程是“不重要”的,“不重要”意味着如果他的主进程结束了但该守护线程没有运行完,守护进程就会被......
  • 网络编辑的使用和知识点,进程线程之间实现交互
    软件开放的框架c/s架构c就是Client客户端就是要去请求数据的s就是Server服务端就是给客服端根据客户的要求提供数据的服务端的必备条件时刻提供服务等待客服端的访问有一个固定的地址能够接受多个服务端的请求(高并发)B/s架构B就是Browser就是一个浏览器充当所有服务端......
  • 线程的三个辅助类
    Semaphore1packagecom.huo.HelperClass;23importjava.util.concurrent.Semaphore;4importjava.util.concurrent.TimeUnit;56/**7*@version1.08*@Author作者名9*@Date2022/9/1311:1810*/11publicclassSemaphoreDemo{12pub......
  • nodejs多线程,真正的非阻塞
    干货:收藏:http://cnodejs.org/topic/518b679763e9f8a5424406e9node从他推出至今,充满赞美和饱受诟病的都是其单线程模型,所有的任务都在一个线程中完成(I/O等例外),优势的地方自然是免去了频繁切换线程的开销,以及减少资源互抢的问题等等,但是当nodejs面对cpu密集型模型的时候就力不从心了......
  • controller是单例模式还是多例模式?spring默认的是单例模式,那么如何保证线程安全
    controller是单例模式还是多例模式在Java中,Controller既可以是单例模式,也可以是多例模式,这取决于具体的实现方式。在单例模式中,Controller只会被实例化一次,多个线程共享同一个实例。这样可以节约系统资源,提高系统性能。但是在多线程环境下,如果不加以保护,可能会出现线程安全的问......