多線程編程
線程在Unix系統(tǒng)下,通常被稱為輕量級(jí)的進(jìn)程。一個(gè)進(jìn)行可以有很都進(jìn)程,每條線程并行執(zhí)行不同的任務(wù)。
多線程的優(yōu)點(diǎn)
線程可以提高應(yīng)用程序在多核環(huán)境下處理諸如文件I/O或者socket I/O等會(huì)產(chǎn)生堵塞的情況的表現(xiàn)性能。在Unix系統(tǒng)中,一個(gè)進(jìn)程包含很多東西,包括可執(zhí)行程序以及一大堆的諸如文件描述符地址空間等資源。在很多情況下,完成相關(guān)任務(wù)的不同代碼間需要交換數(shù)據(jù)。如果采用多進(jìn)程的方式,那么通信就需要在用戶空間和內(nèi)核空間進(jìn)行頻繁的切換,開銷很大。但是如果使用多線程的方式,因?yàn)榭梢允褂霉蚕淼娜肿兞浚跃€程間的通信(數(shù)據(jù)交換)變得非常高效。
多線程使用
**多線程在鏈接時(shí)需使用pthread庫 **
創(chuàng)建線程 pthread_create
線程創(chuàng)建函數(shù)包含四個(gè)變量,分別為:
- 一個(gè)線程變量名,被創(chuàng)建線程的標(biāo)識(shí)
- 線程的屬性指針,缺省為NULL即可
- 被創(chuàng)建線程的程序代碼
- 程序代碼的參數(shù)
For example:
pthread_t thrd1;
pthread_attr_t attr;
void thread_function(void argument);
char *some_argument;
pthread_create(&thrd1, NULL, (void *)&thread_function, (void *) &some_argument);
結(jié)束線程 pthread_exit
線程結(jié)束調(diào)用實(shí)例:
pthread_exit(void *retval); //retval用于存放線程結(jié)束的退出狀態(tài)
線程等待 pthread_join
pthread_create調(diào)用成功以后,新線程和老線程誰先執(zhí)行,誰后執(zhí)行用戶是不知道的,這一塊取決與操作系統(tǒng)對(duì)線程的調(diào)度,如果我們需要等待指定線程結(jié)束,需要使用pthread_join函數(shù),這個(gè)函數(shù)實(shí)際上類似與多進(jìn)程編程中的waitpid。 舉個(gè)例子,以下假設(shè) A 線程調(diào)用 pthread_join 試圖去操作B線程,該函數(shù)將A線程阻塞,直到B線程退出,當(dāng)B線程退出以后,A線程會(huì)收集B線程的返回碼。 該函數(shù)包含兩個(gè)參數(shù):
pthread_t th //th是要等待結(jié)束的線程的標(biāo)識(shí)
void **thread_return //指針thread_return指向的位置存放的是終止線程的返回狀態(tài)。
調(diào)用實(shí)例:
pthread_join(thrd1, NULL);
多線程的同步與互斥
方式一:鎖
在主線程中初始化鎖為解鎖狀態(tài)
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
在編譯時(shí)初始化鎖為解鎖狀態(tài)
鎖初始化 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
訪問對(duì)象時(shí)的加鎖操作與解鎖操作
pthread_mutex_lock(&mutex) // 加鎖
pthread_mutex_unlock(&mutex) // 釋放鎖
方式二:信號(hào)量
鎖有一個(gè)很明顯的缺點(diǎn),那就是它只有兩種狀態(tài):鎖定與不鎖定。
信號(hào)量本質(zhì)上是一個(gè)非負(fù)數(shù)的整數(shù)計(jì)數(shù)器,它也被用來控制對(duì)公共資源的訪問。當(dāng)公共資源增加的時(shí)候,調(diào)用信號(hào)量增加函數(shù)sem_post()對(duì)其進(jìn)行增加,當(dāng)公共資源減少的時(shí)候,調(diào)用函數(shù)sem_wait()來減少信號(hào)量。其實(shí),我們是可以把鎖當(dāng)作一個(gè)0-1信號(hào)量的。
它們是在/usr/include/semaphore.h中進(jìn)行定義的,信號(hào)量的數(shù)據(jù)結(jié)構(gòu)為sem_t, 本質(zhì)上,它是一個(gè)long型整數(shù)
相關(guān)函數(shù)
在使用semaphore之前,我們需要先引入頭文件#include <semaphore.h>
初始化信號(hào)量:int sem_init(sem_t *sem, int pshared, unsigned int value);
成功返回0,失敗返回-1
參數(shù)
sem:指向信號(hào)量結(jié)構(gòu)的一個(gè)指針
pshared: 不是0的時(shí)候,該信號(hào)量在進(jìn)程間共享,否則只能為當(dāng)前進(jìn)程的所有線程們共享
value:信號(hào)量的初始值
信號(hào)量減1操作,當(dāng)sem=0的時(shí)候該函數(shù)會(huì)堵塞 int sem_wait(sem_t *sem);
成功返回0,失敗返回-1
參數(shù)
sem:指向信號(hào)量的一個(gè)指針
信號(hào)量加1操作 int sem_post(sem_t *sem);
參數(shù)與返回同上
銷毀信號(hào)量 int sem_destroy(sem_t *sem);
參數(shù)與返回同上