天天看點

詳解線程的信号量和互斥鎖

  前言:有個問題感覺一直會被問道:程序和線程的差別?也許之前我會回答:

  • 程序:資源配置設定最小機關
  • 線程:輕量級的程序 是系統排程的最小機關 由程序建立 多個線程共享程序的資源

  但是現在我覺得一個比喻回答的更好:程式就像靜止的火車,程序是運作的火車,線程是運作火車的每節車廂。

個人感覺了解遠比背些概念性東西更好。

  一、線程

  通常在一個程序中可以包含若幹個線程,當然一個程序中至少有一個線程,不然沒有存在的意義。線程可以利用程序所擁有的資源,在引入線程的作業系統中,通常都是把程序作為配置設定資源的基本機關,而把線程作為獨立運作和獨立排程的基本機關,由于線程比程序更小,基本上不擁有系統資源,故對它的排程所付出的開銷就會小得多,能更高效的提高系統多個程式間并發執行的程度。

  1、線程相關函數 

  • pthread_create函數

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

void *(*start_routine) (void *), void *arg);

注:Compile and link with -pthread.//編譯時 要加-lpthread

功能:建立線程

參數1:線程的ID

參數2:NULL

參數3:線程處理函數

參數4: 傳遞給線程處理函數的參數

成功放回0 失敗傳回-1

  • pthread_join函數

int pthread_join(pthread_t thread, void **retval);

功能:以阻塞的方式等待指定線程 主線程如果執行到此函數 将阻塞等待子線程結束

  程式1-1示範兩個函數用法:

#include"my.h"

void *func(void *p) 
{
    *(int*)p = 10; 
    printf("%d\n",*(int *)p);
}

int main()
{
    int x=100;
    pthread_t id; 
    int ret = pthread_create(&id,NULL,func,&x);
    if(ret<0)
    {   
        perror("pthread_create");
        exit(-1);
    }   
    pthread_join(id,NULL);
    return 0;

}      

注:頭檔案“my.h”為自定義檔案,詳情請參考這篇部落格:http://www.cnblogs.com/liudw-0215/p/8946879.html  

運作示範如下圖:

詳解線程的信号量和互斥鎖

  二、信号量

  信号量(Semaphore),有時被稱為信号燈,是在多線程環境下使用的一種設施, 它負責協調各個線程, 以保證它們能夠正确、合理的使用公共資源。

  1、信号量相關函數

  • sem_init函數

sem_t s;

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

格式:sem_init(&s,0,n)

功能:初始化一個信号量的值為value

參數2:是否在程序間使用 一般總是0 表示不在程序間使用

參數3:計數器的初始值

  • sem_wait函數

int sem_wait(sem_t *sem);

把計數器減一 它會等待 直到信号量有個非零值才會執行減法操作

如果對值為0的信号量用sem_wait 這個函數會等待 直到其他線程增加該信号量的值 使其不再是0為止

如果對值為2的信号量調用sem_wait 線程會繼續執行 但信号量的值會減一。

如果兩個線程同時在sem_wait調用上等待同一個信号量變為非0值 那麼當信号量 被第三個線程+1 隻有一個等待線程開始對信号量-1

然後繼續執行 另一個線程還繼續等待。

  • sem_post函數

int sem_post(sem_t *sem);

功能:把 計數器+1

  程式2-1介紹信号量使用

#include"my.h"

sem_t s;

void *fun(void *p)
{
    int i;
    int *pa = (int *)p;
    for(i=0;i<4;i++)
    {
        sem_wait(&s);//将計數器的值-1 
        pa[i] +=i;
    }
    for(i=0;i<4;i++)
    {
        printf("%-02d",pa[i]);
    }
    printf("\n");
    return  NULL;
}

void *fun1(void *p)
{
    sem_wait(&s);//将計數器的值-1 
    puts("fun1 run!");
    return NULL;
}

int main()
{
    int i=0,ret=0;
    int a[5]={0};
    sem_init(&s,0,0);//設定信号量的值為0
    pthread_t tid[2];
    ret = pthread_create(&tid[0],NULL,fun,a);
    if(ret<0)
    {
        perror("pthread_create");
        exit(-1);
    }
    ret = pthread_create(&tid[1],NULL,fun1,a);
    if(ret<0)
    {
        perror("pthread_create");
        exit(-1);
    }

    for(i=0;i<5;i++)
    {
        sem_post(&s);//将計數器的值+1  
    }

    pthread_join(tid[0],NULL);
    pthread_join(tid[1],NULL);
    return 0;
}      
詳解線程的信号量和互斥鎖

  三、互斥鎖

  互斥鎖: 隻要被鎖住,其他任何線程都不可以通路被保護的資源

  1、互斥鎖相關函數

pthread_mutex_t m;

pthread_mutex_init(&m,NULL) //初始化互斥量

pthread_mutex_lock(&m);//對一個互斥量加鎖 如果互斥量已經加鎖 函數會一直等待 等到有線程把這個互斥量解鎖後 再去加鎖

pthread_mutex_unlock(&m);//對一個互斥量解鎖 哪個線程加鎖隻能由這個線程解鎖 别的線程不能 解鎖

  程式3-1示範互斥鎖應用:

#include"my.h"

pthread_mutex_t m;

void* thread_fun(void  *p)
{
    int i;
    pthread_mutex_lock(&m);//加鎖
    for(i=0;i<3;i++)
    {
        printf("PID:%d tid:%lu\n",getpid(),pthread_self());
        sleep(1);
    }
    pthread_mutex_unlock(&m);//解鎖
    pthread_exit(NULL);
}

int main()
{
    pthread_mutex_init(&m,NULL);//初始化鎖
    int i,ret;
    pthread_t tid[3];
    for(i=0;i<3;i++)
    {
        ret = pthread_create(&tid[i],NULL,thread_fun,NULL);
        if(ret<0)
        {
            printf("pthread_create  %d error\n",i);
            exit(-1);
        }
    }
    
    
    
    for(i=0;i<3;i++)
    {
        pthread_join(tid[i],NULL);
    }
    return 0;
}      

  運作示範如下圖:

詳解線程的信号量和互斥鎖

總結:主要介紹線程同步的信号量和互斥鎖,以後有時間将更加詳細介紹其中實作原理。

  

作者:

柳德維

出處:

https://www.cnblogs.com/liudw-0215/

-------------------------------------------

個性簽名:獨學而無友,則孤陋而寡聞。做一個靈魂有趣的人!

如果覺得這篇文章對你有小小的幫助的話,記得在右下角點個“推薦”哦,部落客在此感謝!

萬水千山總是情,打賞一分行不行,是以如果你心情還比較高興,也是可以掃碼打賞部落客,哈哈哈(っ•̀ω•́)っ⁾⁾!

繼續閱讀