Linux下c開發 之 線程通信(轉)

1.Linux“線程”

?????進程與線程之間是有區別的,不過Linux內核只提供了輕量進程的支持,未實現線程模型。Linux是一種“多進程單線程”的操作系統。Linux本身只有進程的概念,而其所謂的“線程”本質上在內核里仍然是進程。

?????大家知道,進程是資源分配的單位,同一進程中的多個線程共享該進程的資源(如作為共享內存的全局變量)。Linux中所謂的“線程”只是在被創建時clone了父進程的資源,因此clone出來的進程表現為“線程”,這一點一定要弄清楚。因此,Linux“線程”這個概念只有在打冒號的情況下才是最準確的。

?????目前Linux中最流行的線程機制為LinuxThreads,所采用的就是線程-進程“一對一”模型,調度交給核心,而在用戶級實現一個包括信號處理在內的線程管理機制。LinuxThreads由Xavier Leroy (Xavier.Leroy@inria.fr)負責開發完成,并已綁定在GLIBC中發行,它實現了一種BiCapitalized面向Linux的Posix 1003.1c “pthread”標準接口。Linuxthread可以支持Intel、Alpha、MIPS等平臺上的多處理器系統。

  按照POSIX 1003.1c 標準編寫的程序與Linuxthread 庫相鏈接即可支持Linux平臺上的多線程,在程序中需包含頭文件pthread. h,在編譯鏈接時使用命令:

gcc -D -REENTRANT -lpthread xxx. c

  其中-REENTRANT宏使得相關庫函數(如stdio.h、errno.h中函數) 是可重入的、線程安全的(thread-safe),-lpthread則意味著鏈接庫目錄下的libpthread.a或libpthread.so文件。使用Linuxthread庫需要2.0以上版本的Linux內核及相應版本的C庫(libc 5.2.18、libc 5.4.12、libc 6)。

?????2.“線程”控制

  線程創建

  進程被創建時,系統會為其創建一個主線程,而要在進程中創建新的線程,則可以調用pthread_create:

pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(start_routine)(void*), void *arg);

  start_routine為新線程的入口函數,arg為傳遞給start_routine的參數。

  每個線程都有自己的線程ID,以便在進程內區分。線程ID在pthread_create調用時回返給創建線程的調用者;一個線程也可以在創建后使用pthread_self()調用獲取自己的線程ID:

pthread_self (void) ;

  線程退出

  線程的退出方式有三:

  (1)執行完成后隱式退出;

  (2)由線程本身顯示調用pthread_exit 函數退出;

pthread_exit (void * retval) ;

  (3)被其他線程用pthread_cance函數終止:

pthread_cance (pthread_t thread) ;

  在某線程中調用此函數,可以終止由參數thread 指定的線程。

  如果一個線程要等待另一個線程的終止,可以使用pthread_join函數,該函數的作用是調用pthread_join的線程將被掛起直到線程ID為參數thread的線程終止:

pthread_join (pthread_t thread, void** threadreturn);

3.線程通信

  線程互斥

  互斥意味著“排它”,即兩個線程不能同時進入被互斥保護的代碼。Linux下可以通過pthread_mutex_t 定義互斥體機制完成多線程的互斥操作,該機制的作用是對某個需要互斥的部分,在進入時先得到互斥體,如果沒有得到互斥體,表明互斥部分被其它線程擁有,此時欲獲取互斥體的線程阻塞,直到擁有該互斥體的線程完成互斥部分的操作為止。

  下面的代碼實現了對共享全局變量x 用互斥體mutex 進行保護的目的:

int x; // 進程中的全局變量
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); //按缺省的屬性初始化互斥體變量mutex
pthread_mutex_lock(&mutex); // 給互斥體變量加鎖
… //對變量x 的操作
phtread_mutex_unlock(&mutex); // 給互斥體變量解除鎖

  線程同步

  同步就是線程等待某個事件的發生。只有當等待的事件發生線程才繼續執行,否則線程掛起并放棄處理器。當多個線程協作時,相互作用的任務必須在一定的條件下同步。

  Linux下的C語言編程有多種線程同步機制,最典型的是條件變量(condition variable)。pthread_cond_init用來創建一個條件變量,其函數原型為:

pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr);

  pthread_cond_wait和pthread_cond_timedwait用來等待條件變量被設置,值得注意的是這兩個等待調用需要一個已經上鎖的互斥體mutex,這是為了防止在真正進入等待狀態之前別的線程有可能設置該條件變量而產生競爭。pthread_cond_wait的函數原型為:

pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);

  pthread_cond_broadcast用于設置條件變量,即使得事件發生,這樣等待該事件的線程將不再阻塞:

pthread_cond_broadcast (pthread_cond_t *cond) ;

  pthread_cond_signal則用于解除某一個等待線程的阻塞狀態:

pthread_cond_signal (pthread_cond_t *cond) ;

  pthread_cond_destroy 則用于釋放一個條件變量的資源。

  在頭文件semaphore.h 中定義的信號量則完成了互斥體和條件變量的封裝,按照多線程程序設計中訪問控制機制,控制對資源的同步訪問,提供程序設計人員更方便的調用接口。

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

  這個函數初始化一個信號量sem 的值為val,參數pshared 是共享屬性控制,表明是否在進程間共享。

sem_wait(sem_t *sem);

  調用該函數時,若sem為無狀態,調用線程阻塞,等待信號量sem值增加(post )成為有信號狀態;若sem為有狀態,調用線程順序執行,但信號量的值減一。

sem_post(sem_t *sem);

  調用該函數,信號量sem的值增加,可以從無信號狀態變為有信號狀態。

????? 4.實例

  下面我們還是以名的生產者/消費者問題為例來闡述Linux線程的控制和通信。一組生產者線程與一組消費者線程通過緩沖區發生聯系。生產者線程將生產的產品送入緩沖區,消費者線程則從中取出產品。緩沖區有N 個,是一個環形的緩沖池。

#include <stdio.h>
#include <pthread.h>
#define BUFFER_SIZE 16 // 緩沖區數量
struct prodcons
{
// 緩沖區相關數據結構
int buffer[BUFFER_SIZE]; /* 實際數據存放的數組*/
pthread_mutex_t lock; /* 互斥體lock 用于對緩沖區的互斥操作 */
int readpos, writepos; /* 讀寫指針*/
pthread_cond_t notempty; /* 緩沖區非空的條件變量 */
pthread_cond_t notfull; /* 緩沖區未滿的條件變量 */
};
/* 初始化緩沖區結構 */
void init(struct prodcons *b)
{
pthread_mutex_init(&b->lock, NULL);
pthread_cond_init(&b->notempty, NULL);
pthread_cond_init(&b->notfull, NULL);
b->readpos = 0;
b->writepos = 0;
}
/* 將產品放入緩沖區,這里是存入一個整數*/
void put(struct prodcons *b, int data)
{
pthread_mutex_lock(&b->lock);
/* 等待緩沖區未滿*/
if ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
{
pthread_cond_wait(&b->notfull, &b->lock);
}
/* 寫數據,并移動指針 */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos > = BUFFER_SIZE)
b->writepos = 0;
/* 設置緩沖區非空的條件變量*/
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}
/* 從緩沖區中取出整數*/
int get(struct prodcons *b)
{
int data;
pthread_mutex_lock(&b->lock);
/* 等待緩沖區非空*/
if (b->writepos == b->readpos)
{
pthread_cond_wait(&b->notempty, &b->lock);
}
/* 讀數據,移動讀指針*/
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos > = BUFFER_SIZE)
b->readpos = 0;
/* 設置緩沖區未滿的條件變量*/
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}

/* 測試:生產者線程將1 到10000 的整數送入緩沖區,消費者線
程從緩沖區中獲取整數,兩者都打印信息*/
#define OVER ( - 1)
struct prodcons buffer;
void *producer(void *data)
{
int n;
for (n = 0; n < 10000; n++)
{
printf("%d --->\n", n);
put(&buffer, n);
} put(&buffer, OVER);
return NULL;
}

void *consumer(void *data)
{
int d;
while (1)
{
d = get(&buffer);
if (d == OVER)
break;
printf("--->%d \n", d);
}
return NULL;
}

int main(void)
{
pthread_t th_a, th_b;
void *retval;
init(&buffer);
/* 創建生產者和消費者線程*/
pthread_create(&th_a, NULL, producer, 0);
pthread_create(&th_b, NULL, consumer, 0);
/* 等待兩個線程結束*/
pthread_join(th_a, &retval);
pthread_join(th_b, &retval);
return 0;
}

  5.WIN32、VxWorks、Linux線程類比

  目前為止,筆者已經創作了《基于嵌入式操作系統VxWorks的多任務并發程序設計》(《軟件報》2006年5~12期連載)、《深入淺出Win32多線程程序設計》(天極網技術專題)系列,我們來找出這兩個系列文章與本文的共通點。

   看待技術問題要瞄準其本質,不管是Linux、VxWorks還是WIN32,其涉及到多線程的部分都是那些內容,無非就是線程控制和線程通信,它們的許多函數只是名稱不同,其實質含義是等價的,下面我們來列個三大操作系統共同點詳細表單:

事項WIN32VxWorksLinux
線程創建CreateThreadtaskSpawnpthread_create
線程終止執行完成后退出;線程自身調用ExitThread函數即終止自己;被其他線程調用函數TerminateThread函數執行完成后退出;由線程本身調用exit退出;被其他線程調用函數taskDelete終止執行完成后退出;由線程本身調用pthread_exit 退出;被其他線程調用函數pthread_cance終止
獲取線程IDGetCurrentThreadIdtaskIdSelfpthread_self
創建互斥CreateMutexsemMCreatepthread_mutex_init
獲取互斥WaitForSingleObject、WaitForMultipleObjectssemTakepthread_mutex_lock
釋放互斥ReleaseMutexsemGivephtread_mutex_unlock
創建信號量CreateSemaphoresemBCreate、semCCreatesem_init
等待信號量WaitForSingleObjectsemTakesem_wait
釋放信號量ReleaseSemaphoresemGivesem_post

   6.小結

  本章講述了Linux下多線程的控制及線程間通信編程方法,給出了一個生產者/消費者的實例,并將Linux的多線程與WIN32、VxWorks多線程進行了類比,總結了一般規律。鑒于多線程編程已成為開發并發應用程序的主流方法,學好本章的意義也便不言自明。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/254968.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/254968.shtml
英文地址,請注明出處:http://en.pswp.cn/news/254968.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HDU 1028 Ignatius and the Princess III

//強行遞推。 xx[i][j]表示i數中第j個開頭的組合種類。 /* 最終結果[i]為 sum of(xx[i][j]) (j from 1 to i); xx[i][j]sum of (xx[i-j][k]) (k from 1 to j); 例如 xx[10][4]xx[6][1]xx[6][2]xx[6][3]xx[6][4]; xx[6][1] 1; 6111111; xx[6][2]3; 6222, 62211, 621111; xx[…

HALCON示例程序measure_metal_part_id.hdev使用xld邊緣擬合檢測零件加工是否合格

HALCON示例程序measure_metal_part_id.hdev使用xld邊緣擬合檢測零件加工是否合格 示例程序源碼&#xff08;加注釋&#xff09; 關于顯示類函數解釋 dev_update_off () Imagefiles : [‘metal-parts/metal-part-model-01’,‘metal-parts/metal-parts-01’,‘metal-parts/meta…

編寫批處理文件-------基礎

第一、Windows bat 批處理文件 編寫 如何編寫批處理文件 批處理文件&#xff08;batch file&#xff09;包含一系列 DOS命令&#xff0c;通常用于自動執行重復性任務。 用戶只需雙擊批處理文件便可執行任務&#xff0c;而無需重復輸入相同指令。編寫批處理文件非常簡單&#xf…

主控芯片

主控芯片&#xff1a; 主控芯片里有310&#xff0c;320,3288&#xff0c;288,318&#xff0c;333&#xff0c;345&#xff0c;7501, 其中310是中星微發展比較早&#xff0c;比較成熟的芯片。在現在一般應用在水晶夾子之類的低端產品上。 3288也是低端芯片&#xff0c;318&…

MPEG2、H.263、H.264協議效率對比

[摘錄]1.1 MPEG2、H.263、H.264協議效率對比ITUT中定義的雙向視頻通信協議族包括&#xff1a;H.320、H.323&#xff0c;這兩個協議族中&#xff0c;包含了很多子協議&#xff0c;例如音頻編碼協議、視頻編碼協議等&#xff0c;其中視頻編碼包括&#xff1a;H.261、H.263、H.264…

WebService SOAP、Restful和HTTP(post/get)請求區別

web service&#xff08;SOAP&#xff09; Webservice的一個最基本的目的就是提供在各個不同平臺的不同應用系統的協同工作能力。 Web service 就是一個應用程序&#xff0c;它向外界暴露出一個能夠通過Web進行調用的API。 SOAP是一種簡單基于xml的輕量協議&#xff0c;用戶web…

Block的循環引用詳解

1.首先我們創建了一個網絡請求工具類 然后storyboard里面去創建了一個導航控制器 并且把它設置為初始控制器 然后拖入一個bar button &#xff0d;&#xff0d;show&#xff0d;&#xff0d;到自帶的控制器 這個時候運行代碼的結果是 x 顯然這個時候沒有造成循環引用 為什…

HALCON示例程序measure_pump.hdev螺紋孔位置與尺寸測量

HALCON示例程序measure_pump.hdev螺紋孔位置與尺寸測量 示例程序源碼&#xff08;加注釋&#xff09; 關于顯示類函數解釋 dev_update_var (‘off’) dev_update_off () read_image (Image, ‘pumpe’) get_image_size (Image, Width, Height) dev_close_window () dev_open_…

計算機視覺和圖形學中的攝像機內參數矩陣詳解

在計算機視覺和圖形學中都有“攝像機內參數矩陣”這個概念&#xff0c;其含義大致相同&#xff0c;但在實際使用過程中&#xff0c;這兩個矩陣卻相差甚遠。在增強現實中&#xff0c;為了使計算機繪制的虛擬物體和真實環境圖像對其&#xff0c;需要令虛擬攝像機的內參數和真實攝…

c#和html方法互調

具體見連接&#xff1a;https://www.cnblogs.com/zeroLove/p/3912460.html轉載于:https://www.cnblogs.com/gaara-zhang/p/8746403.html

數據庫基礎雜記

sql,Structured Query Language結構化查詢語言。SQL 是一門 ANSI(美國國家標準局) 的標準計算機語言&#xff0c;用來訪問和操作數據庫系統。SQL 語句用于取回和更新數據庫中的數據。SQL 可與數據庫程序協同工作&#xff0c;比如 MS Access、DB2、Informix、MS SQL Server、Ora…

很有用的X264和ffmpeg的設置

很有用的X264和FFMPEG的設置 http://www.360doc.com/content/11/0209/16/3705984_91612512.shtml 點擊打開鏈接

HALCON示例程序measure_ring.hdev齒輪齒寬度測量

HALCON示例程序measure_ring.hdev齒輪齒寬度測量 示例程序源碼&#xff08;加注釋&#xff09; 關于顯示類函數解釋 read_image (Image, ‘rings_and_nuts’) dev_close_window () dev_open_window_fit_image (Image, 0, 0, 640, 640, WindowHandle) set_display_font (Windo…

基于RBGD的mapping

最近學習RGBD的SLAM&#xff0c;收集了兩個RGBD的mapping的開源工具包 1.RGBDSlam2 a.安裝方法&#xff1a; #準備工作空間 source /opt/ros/indigo/setup.bash mkdir -p ~/rgbdslam_catkin_ws/src cd ~/rgbdslam_catkin_ws/src catkin_init_workspace cd ~/rgbdslam_catkin_ws…

【瓜分5000元獎金】Wannafly挑戰賽13

鏈接&#xff1a;https://www.nowcoder.com/acm/contest/80/A來源&#xff1a;牛客網 zzy的小號 時間限制&#xff1a;C/C 1秒&#xff0c;其他語言2秒空間限制&#xff1a;C/C 262144K&#xff0c;其他語言524288K64bit IO Format: %lld題目描述 學家zzy根據字體的特點&#…

X264參數設定詳細解釋

x264 core:65 r1074M b6bb3d4 Syntax: x264 [options] -o outfile infile [widthxheight] 語法(命令行寫法)&#xff1a;x264 [參數] -o 輸出文件名 輸入文件名 [寬x高] 范例&#xff1a; x264 --crf 26 --ref 3 --mixed-refs --bframes 3 --b-adapt 2 --b-pyramid --weightb -…

20145217《網絡對抗》 惡意代碼分析

20145217《網絡對抗》 免殺原理與實踐 知識點學習總結 進行惡意代碼分析之前必須具備以下知識&#xff1a;編程、匯編/反匯編、網絡基本知識、PE文件結構以及一些常用行為分析軟件。 一、在一個已經感染了惡意代碼的機器上如何找到病毒文件&#xff1f; 找到惡意代碼才能對其分…

HALCON示例程序measure_screw.hdev螺紋尺寸測量

HALCON示例程序measure_screw.hdev螺紋尺寸測量 示例程序源碼&#xff08;加注釋&#xff09; 關于顯示類函數解釋 dev_update_off () read_image (Image, ‘screw_thread’) get_image_pointer1 (Image, Pointer, Type, Width, Height) dev_close_window () dev_open_window…

邊工作邊刷題:70天一遍leetcode: day 97-2

Design Hit Counter 要點&#xff1a;因為是second granularity&#xff0c;所以可以用以秒為單位的circular buffer方法。這題簡單在只需要count過去300秒的&#xff0c;增加難度可以count過去秒&#xff0c;分鐘&#xff0c;小時。 2個時間點都有可能更新超時的統計&#xff…

cvRemap 對圖像進行普通幾何變換

cvRemap 對圖像進行普通幾何變換 函數 cvRemap 利用下面指定的矩陣變換輸入圖像:   dst(x,y)<-src(mapx(x,y),mapy(x,y))   與其它幾何變換類似&#xff0c;可以使用一些插值方法&#xff08;由用戶指定&#xff0c;同cvResize&#xff09;來計算非整數坐標的像素值 vo…