Linux多線程編程五(信號量)

1、什麼是信號量數組

      線程的信號量與進程間通訊中使用的信號量的概念是同樣,它是一種特殊的變量,它能夠被增長或減小,但對其的關鍵訪問被保證是原子操做。若是一個程序中有多個線程試圖改變一個信號量的值,系統將保證全部的操做都將依次進行。多線程

      而只有0和1兩種取值的信號量叫作二進制信號量,在這裏將重點介紹。而信號量通常經常使用於保護一段代碼,使其每次只被一個執行線程運行。咱們可使用二進制信號量來完成這個工做。函數


2、信號量接口post


      信號量的函數都以sem_開頭,線程中使用的基本信號量函數有4個,它們都聲明在頭文件semaphore.h中。spa

一、sem_init函數線程

     該函數用於建立信號量,其原型以下:對象

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

    該函數初始化由sem指向的信號對象,設置它的共享選項,並給它一個初始的整數值。pshared控制信號量的類型,若是其值爲0,就表示這個信號量是當前進程的局部信號量,不然信號量就能夠在多個進程之間共享,value爲sem的初始值。調用成功時返回0,失敗返回-1.進程

二、sem_wait函數字符串

       該函數用於以原子操做的方式將信號量的值減1。原子操做就是,若是兩個線程企圖同時給一個信號量加1或減1,它們之間不會互相干擾。它的原型以下:

int sem_wait(sem_t *sem);  

sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1.

函數sem_trywait ( sem_t *sem )是函數sem_wait()的非阻塞版本,它直接將信號量sem的值減一。

三、sem_post函數

該函數用於以原子操做的方式將信號量的值加1。它的原型以下:

int sem_post(sem_t *sem);

與sem_wait同樣,sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1.

四、sem_destroy函數

該函數用於對用完的信號量的清理。它的原型以下:

int sem_destroy(sem_t *sem);  

成功時返回0,失敗時返回-1.

五、獲得信號量值

int sem_getvalue (sem_t* sem);


3、使用信號量同步線程

       下面以一個簡單的多線程程序來講明如何使用信號量進行線程同步。在主線程中,咱們建立子線程,並把數組msg做爲參數傳遞給子線程,而後主線程等待直到有文本輸入,而後調用sem_post來增長信號量的值,這樣就會馬上使子線程從sem_wait的等待中返回並開始執行。線程函數在把字符串的小寫字母變成大寫並統計輸入的字符數量以後,它再次調用sem_wait並再次被阻塞,直到主線程再次調用sem_post增長信號量的值。

#include <unistd.h>

#include <pthread.h>

#include <semaphore.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>


//線程函數

void *thread_func(void *msg);

sem_t sem;//信號量


#define MSG_SIZE 512


int main()

{

int res = -1;

pthread_t thread;

void *thread_result = NULL;

char msg[MSG_SIZE];

//初始化信號量,其初值爲0

res = sem_init(&sem, 0, 0);

if(res == -1)

{

perror("semaphore intitialization failed\n");

exit(EXIT_FAILURE);

}

//建立線程,並把msg做爲線程函數的參數

res = pthread_create(&thread, NULL, thread_func, msg);

if(res != 0)

{

perror("pthread_create failed\n");

exit(EXIT_FAILURE);

}

//輸入信息,以輸入end結束,因爲fgets會把回車(\n)也讀入,因此判斷時就變成了「end\n」

printf("Input some text. Enter 'end'to finish...\n");

while(strcmp("end\n", msg) != 0)

{

fgets(msg, MSG_SIZE, stdin);

//把信號量加1

sem_post(&sem);

}


printf("Waiting for thread to finish...\n");

//等待子線程結束

res = pthread_join(thread, &thread_result);

if(res != 0)

{

perror("pthread_join failed\n");

exit(EXIT_FAILURE);

}

printf("Thread joined\n");

//清理信號量

sem_destroy(&sem);

exit(EXIT_SUCCESS);

}


void* thread_func(void *msg)

{

//把信號量減1

sem_wait(&sem);

char *ptr = msg;

while(strcmp("end\n", msg) != 0)

{

int i = 0;

//把小寫字母變成大寫

for(; ptr[i] != '\0'; ++i)

{

if(ptr[i] >= 'a' && ptr[i] <= 'z')

{

ptr[i] -= 'a' - 'A';

}

}

printf("You input %d characters\n", i-1);

printf("To Uppercase: %s\n", ptr);

//把信號量減1

sem_wait(&sem);

}

//退出線程

pthread_exit(NULL);

}

相關文章
相關標籤/搜索