關於一點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進入等待狀態\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);
}

根據前面兩條規則,我們可以知道,如果多個線程同時調用這個函數,當一個線程取得同步鎖之后,其他線程就會阻塞在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\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);

    //修改
    //pthread_mutex_lock(&mutex);

    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(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進入等待狀態\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);
}

最后的輸出是:

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\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);

    //修改
    pthread_mutex_lock(&mutex);

    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(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進入等待狀態\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);
}

注意帶注釋的地方,在執行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函數最后不釋放互斥鎖,最后只會有第一個跑出來的線程解套成功。所以,從目前來看,我的分析應該是正確的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM