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函数最后不释放互斥锁,最后只会有第一个跑出来的线程解套成功。所以,从目前来看,我的分析应该是正确的。

  • 相关阅读:
    什么是ORM
    ORM优缺点
    Azure 中快速搭建 FTPS 服务
    连接到 Azure 上的 SQL Server 虚拟机(经典部署)
    在 Azure 虚拟机中配置 Always On 可用性组(经典)
    SQL Server 2014 虚拟机的自动备份 (Resource Manager)
    Azure 虚拟机上的 SQL Server 常见问题
    排查在 Azure 中新建 Windows 虚拟机时遇到的经典部署问题
    上传通用化 VHD 并使用它在 Azure 中创建新 VM
    排查在 Azure 中新建 Windows VM 时遇到的部署问题
  • 原文地址:https://www.cnblogs.com/liulipeng/p/3552767.html
Copyright © 2011-2022 走看看