1. 程式人生 > >詳解線程的信號量和互斥鎖

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

pthread.h 擁有 分享圖片 .html post 並發 並發執行 格式 引入

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

  • 進程:資源分配最小單位
  • 線程:輕量級的進程 是系統調度的最小單位 由進程創建 多個線程共享進程的資源

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

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

  一、線程

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

  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函數

#include <pthread.h>

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函數

#include <semaphore.h>

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;
}

  運行演示如下圖:

技術分享圖片

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

  

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