zoukankan      html  css  js  c++  java
  • 关于一点pthread_cond_t条件锁的思考以及实验

    转:http://blog.csdn.net/aniao/article/details/5802015

    APUE上,关于条件锁。其中有这么几条总结:

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

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

    好,现在考虑到这一点,假如有如下函数:

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

    根据前面两条规则,我们可以知道,如果多个线程同时调用这个函数,当一个线程取得同步锁之后,其他线程就会阻塞在pthread_mutex_lock函数,而当那个取得锁的线程执行到pthread_cond_wait并阻塞之后,在从这个函数返回(条件满足)之前,会释放掉锁,所以其他线程也能一个一个都执行到pthread_cond_wait这里阻塞。这时就有多个线程阻塞在这里了。

    假设这时候在另外某个线程条件被满足,并发出了pthread_cond_signal,那么这么多阻塞的线程会不会全部一下就都被解开了呢?

    答案是否。

    因为根据第二条规则,从阻塞的函数返回并尝试再次锁住互斥锁,这是一个原子操作。也就是说,第一个成功解套的线程会再次锁上互斥锁,而其他线程这时候要想跳出阻塞状态就不可能了,因为他们无法取得互斥锁,只能继续等待(根据我的测试是等待下一次pthread_cond_singal。

    (以上是错误的,后来发现,原来pthread_cond_signal本来就只会唤醒一个条件锁,而实验证明,唤醒的顺序跟阻塞在条件锁的顺序相同)

    #include <stdio.h>
    #include <error.h>
    #include <pthread.h>
    #include <unistd.h>
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t cond_l = PTHREAD_COND_INITIALIZER;
    
    int i = 1;
    void* run(void *);
    
    void main(int argc, char **argv)
    {
        pthread_t pid1;
        pthread_t pid2;
        pthread_t pid3;
        pthread_t pid4;
    
        pthread_create(&pid1, NULL, run, NULL );
        printf("new thread:%u
    ", (unsigned int)pid1);
        sleep(1);
    
        pthread_create(&pid2, NULL, run, NULL );
        printf("new thread:%u
    ", (unsigned int)pid2);
        sleep(1);
    
        pthread_create(&pid3, NULL, run, NULL );
        printf("new thread:%u
    ", (unsigned int)pid3);
        sleep(1);
    
        pthread_create(&pid4, NULL, run, NULL );
        printf("new thread:%u
    ", (unsigned int)pid4);
        sleep(1);
    
        //修改
        //pthread_mutex_lock(&mutex);
    
        i = 2;
        pthread_cond_signal(&cond_l);
        printf("release signal
    ");
        sleep(1);
    
        i = 2;
        pthread_cond_signal(&cond_l);
        printf("release signal
    ");
        sleep(1);
    
        pthread_join(pid1, NULL );
        pthread_join(pid2, NULL );
        pthread_join(pid3, NULL );
        pthread_join(pid4, NULL );
    }
    
    void* run(void *s)
    {
        pthread_mutex_lock(&mutex);
        while(i == 1)
        {
            printf("线程%u进入等待状态
    ", (unsigned int)pthread_self());
            pthread_cond_wait(&cond_l, &mutex);
        }
        printf("已经解开%u
    ", (unsigned int)pthread_self());
        pthread_mutex_unlock(&mutex);
        i = 1;
    
        return ((void *) 1);
    }

    最后的输出是:

    new thread:3085007776

    线程3085007776进入等待状态

    new thread:3076615072

    线程3076615072进入等待状态

    new thread:3068222368

    线程3068222368进入等待状态

    new thread:3059829664

    线程3059829664进入等待状态

    release signal

    已经解开3085007776

    release signal

    已经解开3076615072

    一切正常,每次pthread_cond_signal就能放掉一个线程。那么为了验证前面我的分析是正确的,加入在执行pthread_cond_signal的时候,阻塞在对应条件锁的pthread_cond_wait处的线程的互斥锁全都是被锁住的,还会有线程能成功解套么?看以下代码:

    #include <stdio.h>
    #include <error.h>
    #include <pthread.h>
    #include <unistd.h>
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t cond_l = PTHREAD_COND_INITIALIZER;
    
    int i = 1;
    void* run(void *);
    
    void main(int argc, char **argv)
    {
        pthread_t pid1;
        pthread_t pid2;
        pthread_t pid3;
        pthread_t pid4;
    
        pthread_create(&pid1, NULL, run, NULL );
        printf("new thread:%u
    ", (unsigned int)pid1);
        sleep(1);
    
        pthread_create(&pid2, NULL, run, NULL );
        printf("new thread:%u
    ", (unsigned int)pid2);
        sleep(1);
    
        pthread_create(&pid3, NULL, run, NULL );
        printf("new thread:%u
    ", (unsigned int)pid3);
        sleep(1);
    
        pthread_create(&pid4, NULL, run, NULL );
        printf("new thread:%u
    ", (unsigned int)pid4);
        sleep(1);
    
        //修改
        pthread_mutex_lock(&mutex);
    
        i = 2;
        pthread_cond_signal(&cond_l);
        printf("release signal
    ");
        sleep(1);
    
        i = 2;
        pthread_cond_signal(&cond_l);
        printf("release signal
    ");
        sleep(1);
    
        pthread_join(pid1, NULL );
        pthread_join(pid2, NULL );
        pthread_join(pid3, NULL );
        pthread_join(pid4, NULL );
    }
    
    void* run(void *s)
    {
        pthread_mutex_lock(&mutex);
        while(i == 1)
        {
            printf("线程%u进入等待状态
    ", (unsigned int)pthread_self());
            pthread_cond_wait(&cond_l, &mutex);
        }
        printf("已经解开%u
    ", (unsigned int)pthread_self());
        pthread_mutex_unlock(&mutex);
        i = 1;
    
        return ((void *) 1);
    }

    注意带注释的地方,在执行pthread_cond_signal之前,我又把互斥锁锁住了。之所以这里敢这么写,是因为其他几个子线程最后卡在pthread_cond_wait的时候都会把锁给释放掉的,所以我能在主线程里取得互斥锁。这样的话,其他子线程接到条件满足的信号后还会从等待中跳出来吗?运行结果如下:

    new thread:3085290400

    线程3085290400进入等待状态

    new thread:3076897696

    线程3076897696进入等待状态

    new thread:3068504992

    线程3068504992进入等待状态

    new thread:3060112288

    线程3060112288进入等待状态

    release signal

    release signal

    Oh,No,果然,没有一个线程跑出来。事实上,如果不是这么改,而是让每个线程在run函数最后不释放互斥锁,最后只会有第一个跑出来的线程解套成功。所以,从目前来看,我的分析应该是正确的。

  • 相关阅读:
    springboot定时任务框架Quartz
    Linux中安装Erlang
    prometheus常用函数详解
    Prometheus+Grafana+SpringBoot业务埋点可视化监控
    Prometheus+Grafana可视化监控SpringBoot项目
    prometheus的数据类型介绍
    DS:顺序栈
    DS:顺序队列
    Linux:06进程
    primer5:chap09顺序容器
  • 原文地址:https://www.cnblogs.com/liulipeng/p/3552767.html
Copyright © 2011-2022 走看看