linux下一個程序中多執行緒的資源共享
在說執行緒資源共享之前,我們先來說來說一下執行緒的概念,執行緒是程序內部的一條執行序列(即執行流),一個程序至少有一個執行緒,即main函式代表的執行流。當然我們也可以通過執行緒庫來建立新的執行緒,這種執行緒我們稱之為函式執行緒,同一個程序中的所有普執行緒是併發執行的。而這些執行緒的一些資源是共享的,我們先來說檔案描述符。
大家先來看下面一段程式碼:
#include<unistd.h> #include<stdio.h> #include<pthread.h> #include<assert.h> #include<fcntl.h> void * fun(void *arg) { sleep(1); int fd=(int)arg; char ar[128]={0}; int n=read(fd,ar,6); printf("%s\n",ar); return NULL; } int main() { int fd=open("a.txt",O_RDONLY); assert(fd!=-1); pthread_t id; int res=pthread_create(&id,NULL,fun,(void*)fd); assert(res==0); int i=0; for(;i<2;i++) { char buff[128]={0}; int n=read(fd,buff,3); printf("%s\n",buff); sleep(2); } close(fd); pthread_exit(NULL); }
這是a.txt裡的內容
這是程式碼的執行結果:
我們先來看程式碼,程式碼很簡單在main執行緒裡我們主要是讀取檔案中三個長度的內容,在函式執行緒裡我們選擇讀取六個長度的內容,程式碼中沉睡時間使我們控制了讀取順序,先列印三個字元睡眠的兩秒過程中另一個執行緒併發執行列印六個字元,之後在列印三個字元,我們可以發現,在讀取過程中,我們通過建立函式執行緒時傳遞的引數實現了檔案的描述符的共享並且根據打印出的資料結合我們學過的檔案資料讀取機制我們可以發現兩個執行緒之間確實對於檔案描述符是共享的。
接下來我們將程式碼做一點小小的變動:
#include<unistd.h> #include<stdio.h> #include<pthread.h> #include<assert.h> #include<fcntl.h> void * fun(void *arg) { sleep(1); int fd=(int)arg; char ar[128]={0}; int n=read(fd,ar,6); printf("%s\n",ar); return NULL; } int main() { int fd=open("a.txt",O_RDONLY); assert(fd!=-1); pthread_t id; int res=pthread_create(&id,NULL,fun,(void*)fd); assert(res==0); int i=0; for(;i<2;i++) { char buff[128]={0}; int n=read(fd,buff,3); printf("%s\n",buff); } sleep(3); close(fd); pthread_exit(NULL); }
a.txt裡的內容不變,執行結果如下:
結合檔案讀取機制這樣的結果我們可以發現檔案描述符確實共享。
接下來我們再來看一下資料空間的共享,首先我們來說堆區空間的共享。
大家看下面一段程式碼:
#include<unistd.h> #include<stdio.h> #include<pthread.h> #include<assert.h> #include<stdlib.h> void *fun (void *arg) { int *ar=(int*)arg; sleep(1); int i=0; for(;i<3;i++) { printf("fun runnig\n"); printf("%d\n",ar[i]); sleep(1); } pthread_exit(NULL); } int main() { printf("main running\n"); int *ar=(int *)malloc(sizeof(int)*3); int i=0; pthread_t id; pthread_create(&id,NULL,fun,ar); for(;i<3;++i) { ar[i]=i; } pthread_join(id,NULL); pthread_exit(NULL); }
我們在堆區開闢一塊資料空間,對其資料進行寫入,然後在建立函式執行緒時將開闢的陣列的空間的地址傳入,在函式執行緒內部實現對堆區資料的讀取,程式碼執行結果如下:
我們可以看到,函式程序準確無誤的訪問到了我們的堆區資料並且將它輸出,也可與證明我們執行緒之間的堆區資料確實是共享的。
接下來我們做的事情是對上面的程式碼進行細小的改動,將在堆區的申請空間改為在棧區申請一部分空間儲存資料,改動如下:
我們將上述程式碼中的int *ar=(int *)malloc(sizeof(int)*3);改為int ar[3]={0};其餘不做改變,重新編譯執行後我們得到的結果與之前一樣,執行結果依舊沒有改變,可以說明棧區空間資料依然共享。
陣列如此,我們的單個變數也是如此,但是要注意單個變數在值傳遞過程中要注意我們的pthraed_create()函式的 最後一個引數型別是void *,因此我們進行值傳遞的過程中要注意型別的轉換以及我們的void*型別是四位元組大小,因此大於四位元組的資料型別的值是無法傳遞的。