互斥鎖的概念及使用


在上一篇博客中我們提到多線程共享同一個資源,怎麼解決多個線程之間共享同一個共享資源,是多線程編程需要考慮的一個問題!本章將會對此問題做出解答!首先我們先了解一下互斥鎖

互斥鎖的概念及使用

1、在編程中,用互斥鎖來保證共享數據操作的完整性,在訪問共享資源前對互斥量進行加鎖,在訪問完成後釋放互斥量。對互斥量進行上鎖以後,其他試圖再次對互斥量加鎖的線程都會被阻塞直到當前線程釋放該互斥鎖。我們可以舉個簡單的例子,可以有助於大家的理解!
試想一下,我們大學宿舍只有一個洗手間,那宿舍四個人怎麼解決馬桶共享的問題?這就需要鎖的機制來解決,馬桶就是臨界資源,我們進入洗手間(臨界區)後,首先上鎖;然後用完離開洗手間(臨界區)之後,把鎖釋放供其他人使用。如果有人想去洗手間時發現門鎖上了,他也有兩種策略:1、在洗手間那裏等(阻塞); 2、暫時先離開等會再過來看(非阻塞)。
2、互斥鎖的使用
int pthread_mutex_lock(pthread_mutex_t* mutex); //申請鎖並上鎖(阻塞鎖);

int pthread_mutex_trylock(pthread_mutex_t* mutex); //申請鎖,並測試上鎖(非阻塞鎖)

int pthread_mutex_unlock (pthread_mutex_t* mutex); //解鎖

int pthread_mutex_destroy (pthread_mutex_t* mutex); //互斥鎖使用完之後,將它摧毀釋放

互斥鎖解決多線程代碼示例

上篇博客寫了多線程編程,此代碼將解決上個博客出現的問題!

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
void *thread_worker1(void *args);
void *thread_worker2(void *args);
//爲什麼要定義一個結構體那?因爲在創建給線程執行函數傳參的時候只能傳一個參數,而我們要傳遞共享變量shared_var
//和相應的互斥鎖lock,所以需要將他們用struct封裝給起來
typedef struct worker_ctx_s
{
    int               shared_var;
    pthread_mutex_t   lock;
}worker_ctx_t;

int main (int argc, char **argv)
{
    worker_ctx_t            worker_ctx;//定義一個結構體變量
    pthread_t               tid;//定義一個線程
    pthread_attr_t          thread_attr;//定義線程屬性

    worker_ctx.shared_var = 1000;
    pthread_mutex_init(&worker_ctx.lock,NULL);//初始化互斥鎖


if(pthread_attr_init(&thread_attr))//初始化線程
{
    printf("pthread_attr_init()failure:%s\n",strerror(errno));
    return -1;
}
if(pthread_attr_setstacksize(&thread_attr,120*1024))//設置線程屬性棧的大小
{
    printf("pthread_attr_setstacksize()failure:%s\n",strerror(errno));
    return -2;
}
if(pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED))//設置線程爲可分離狀態
{
    printf("pthread_attr_setdetachstate()failure:%s\n",strerror(errno));
    return -3;
}
pthread_create(&tid,&thread_attr,thread_worker1,&worker_ctx);//&tid,用來返回該線程的id,第二個參數是線程的屬性,第三個參數是子線程要完成的任務,第四個參數是傳給所調用的函數的指針
printf("Thread worker1 tid[%ld]created ok\n",tid);

pthread_create(&tid,&thread_attr,thread_worker2,&worker_ctx);
printf("Thread worker2 tid[%ld]created ok\n",tid);


while(1)
{
    printf("main thread shared_var:%d\n",worker_ctx.shared_var);
    sleep(10);
}
    pthread_mutex_destroy(&worker_ctx.lock);//互斥鎖使用完之後,將它摧毀釋放
}
void *thread_worker1(void *args)
{
    worker_ctx_t  *ctx = (worker_ctx_t *)args;

    if( !args )
    {
        printf("%s()get invalid arguments\n", __FUNCTION__);
        pthread_exit(NULL);
    }
    printf("Thread worker1 [%ld]start running..\n",pthread_self());//打印自己的線程id
    while(1)
    {
        pthread_mutex_lock(&ctx->lock);//請求鎖並上鎖


        printf("+++ %s before shared_var++:%d\n", __FUNCTION__,ctx->shared_var);
        ctx->shared_var ++;
        sleep(2);
        printf("+++:%s after sleep shared_var:%d\n", __FUNCTION__,ctx->shared_var);
        pthread_mutex_unlock(&ctx->lock);//解鎖
        sleep(1); //這裏都要加上延時,否則一個線程拿到鎖之後會一直佔有該鎖;另外一個線程則不能獲取到鎖;
    }
    printf("Thread worker 1 exit...\n");

    return NULL;
}
void *thread_worker2(void *args)
{
    worker_ctx_t          *ctx=(worker_ctx_t *)args;

    if(!args)
    {
        printf("%s()get invalid arguments\n",__FUNCTION__);
        pthread_exit(NULL);
    }


    printf("Thread worker2 [%ld]start running..\n",pthread_self());

    while(1)
    {
        if(0 !=pthread_mutex_trylock(&ctx->lock))//測試鎖並上鎖
        {
            continue;
        }
        printf("--- %s before shared_var++:%d\n", __FUNCTION__,ctx->shared_var);
        ctx->shared_var ++;
        sleep(2);
        printf("---:%s after sleep shared_var:%d\n", __FUNCTION__,ctx->shared_var);
        sleep(1);// 加上延時,否則一個線程拿到鎖之後會一直佔有該鎖;另外一個線程則不能獲取到鎖;
    }
    printf("Thread worker 2 exit...\n");
    return NULL;
}

代碼運行結果:

在這裏插入圖片描述代碼分析:可以看出來thread_worker1 在創建後首先開始運行,在開始自加之前值爲初始1000,然後讓該值自加後休眠2秒後再打印該值就是1001了,不再是1002了,這就是鎖的機制!如有錯誤的地方,還請下方提出,我將進行改正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章