- 論壇徽章:
- 0
|
多線程編程快速撐握
=============================================
原文出自:
http://atg.cublog.cn/
作者: 董 暉 2006-03-05
注: 轉(zhuǎn)載請(qǐng)注明原文出處
最近在unix sco 下搞多線程編程, 開(kāi)始也摸不著頭腦, 經(jīng)過(guò)幾天的周折總算是搞出來(lái)了!
如果您想了解多線程編程那你找對(duì)文章了!!!
但如果您是這方面的專家,那希望您花一點(diǎn)寶貴的時(shí)間讀完本文! 把我寫(xiě)得不對(duì)與不足的地方
指出來(lái)! Email:
atgjplh@126.com
1. 線程
線程通常叫做輕型的進(jìn)程。雖然這個(gè)叫法有些簡(jiǎn)單化,但這有利于了解線程的概念。
因?yàn)榫程和進(jìn)程比起來(lái)很小,所以相對(duì)來(lái)說(shuō),線程花費(fèi)更少的CPU資源。進(jìn)程往往需要它們自己的資源,
但線程之間可以共享資源,所以線程更加節(jié)省內(nèi)存。Mach的線程使得程序員可以編寫(xiě)并發(fā)運(yùn)行的程序,
而這些程序既可以運(yùn)行在單處理器的機(jī)器上,也可以運(yùn)行在多處理器的機(jī)器中。另外,在單處理器環(huán)境中,
當(dāng)應(yīng)用程序執(zhí)行容易引起阻塞和延遲的操作時(shí),線程可以提高效率。
使用多線程的理由之一是和進(jìn)程相比,它是一種非常"節(jié)儉"的多任務(wù)操作方式。我們知道,在Linux系統(tǒng)下,
啟動(dòng)一個(gè)新的進(jìn)程必須分配給它獨(dú)立的地址空間,建立眾多的數(shù)據(jù)表來(lái)維護(hù)它的代碼段、堆棧段和數(shù)據(jù)段,
這是一種"昂貴"的多任務(wù)工作方式。而運(yùn)行于一個(gè)進(jìn)程中的多個(gè)線程,它們彼此之間使用相同的地址空間,
共享大部分?jǐn)?shù)據(jù),啟動(dòng)一個(gè)線程所花費(fèi)的空間遠(yuǎn)遠(yuǎn)小于啟動(dòng)一個(gè)進(jìn)程所花費(fèi)的空間,而且,
線程間彼此切換所需的時(shí)間也遠(yuǎn)遠(yuǎn)小于進(jìn)程間切換所需要的時(shí)間。據(jù)統(tǒng)計(jì),總的說(shuō)來(lái),一個(gè)進(jìn)程的開(kāi)銷大約是一
個(gè)線程開(kāi)銷的30倍左右,當(dāng)然,在具體的系統(tǒng)上,這個(gè)數(shù)據(jù)可能會(huì)有較大的區(qū)別。
使用多線程的理由之二是線程間方便的通信機(jī)制。對(duì)不同進(jìn)程來(lái)說(shuō),它們具有獨(dú)立的數(shù)據(jù)空間,
要進(jìn)行數(shù)據(jù)的傳遞只能通過(guò)通信的方式進(jìn)行,這種方式不僅費(fèi)時(shí),而且很不方便。線程則不然,
由于同一進(jìn)程下的線程之間共享數(shù)據(jù)空間,所以一個(gè)線程的數(shù)據(jù)可以直接為其它線程所用,這不僅快捷,而且方便。
當(dāng)然,數(shù)據(jù)的共享也帶來(lái)其他一些問(wèn)題,有的變量不能同時(shí)被兩個(gè)線程所修改,有的子程序中聲明為static
的數(shù)據(jù)更有可能給多線程程序帶來(lái)災(zāi)難性的打擊,這些正是編寫(xiě)多線程程序時(shí)最需要注意的地方。
除了以上所說(shuō)的優(yōu)點(diǎn)外,不和進(jìn)程比較,多線程程序作為一種多任務(wù)、并發(fā)的工作方式,當(dāng)然有以下的優(yōu)點(diǎn):
1) 提高應(yīng)用程序響應(yīng)。這對(duì)圖形界面的程序尤其有意義,當(dāng)一個(gè)操作耗時(shí)很長(zhǎng)時(shí),整個(gè)系統(tǒng)都會(huì)等待這個(gè)操作,
此時(shí)程序不會(huì)響應(yīng)鍵盤(pán)、鼠標(biāo)、菜單的操作,而使用多線程技術(shù),將耗時(shí)長(zhǎng)的操作(time consuming)置于一個(gè)新的線程,
可以避免這種尷尬的情況。
2) 使多CPU系統(tǒng)更加有效。操作系統(tǒng)會(huì)保證當(dāng)線程數(shù)不大于CPU數(shù)目時(shí),不同的線程運(yùn)行于不同的CPU上。
3) 改善程序結(jié)構(gòu)。一個(gè)既長(zhǎng)又復(fù)雜的進(jìn)程可以考慮分為多個(gè)線程,成為幾個(gè)獨(dú)立或半獨(dú)立的運(yùn)行部分,
這樣的程序會(huì)利于理解和修改。
2. 線程編程介紹
用子函數(shù)pthread_create創(chuàng)建一個(gè)新的線程。它有四個(gè)參數(shù):一個(gè)用來(lái)保存線程的線程變量、一個(gè)線程屬性、
當(dāng)線程執(zhí)行時(shí)要調(diào)用的函數(shù)和一個(gè)此函數(shù)的參數(shù)。
例如:
pthread_ta_thread ;
pthread_attr_ta_thread_attribute ;
void thread_function(void *argument);
char * some_argument;
pthread_create( &a_thread, a_thread_attribute, (void *)&thread_function,
(void *) &some_argument);
線程屬性只指明了需要使用的最小的堆棧大小。在以后的程序中,線程的屬性可以指定其他的值,
但現(xiàn)在大部分的程序可以使用缺省值。不像UNIX系統(tǒng)中使用fork系統(tǒng)調(diào)用創(chuàng)建的進(jìn)程,它們和它們的父進(jìn)程使用同一個(gè)執(zhí)行點(diǎn),
線程使用在pthread_create中的參數(shù)指明要開(kāi)始執(zhí)行的函數(shù)。
現(xiàn)在我們可以編制第一個(gè)程序了。我們編制一個(gè)多線程的應(yīng)用程序,在標(biāo)準(zhǔn)輸出中打印“Hello Wo r l d”。
首先我們需要兩個(gè)線程變量,一個(gè)新線程開(kāi)始執(zhí)行時(shí)可以調(diào)用的函數(shù)。我們還需要指明每一個(gè)線程應(yīng)該打印的信息。
一個(gè)做法是把要打印的字符串分開(kāi),給每一個(gè)線程一個(gè)字符串作為開(kāi)始的參數(shù)。
請(qǐng)看下面的代碼:
void print_message_function( void *ptr );
main( )
{
pthread_t thread1, thread2;
char *message1 = "Hello";
char *message2 = "Wo r l d " ;
pthread_create( &thread1, pthread_attr_default,
(void*)&print_message_function, (void*) message1);
pthread_create(&thread2, pthread_attr_default,
(void*)&print_message_function, (void*) message2);
exit( 0 ) ;
}
void print_message_function( void *ptr )
{
char *message;
message = (char *) ptr;
printf("%s ", message);
}
程序通過(guò)調(diào)用pthread_create創(chuàng)建第一個(gè)線程,并將“Hello”作為它的啟動(dòng)參數(shù)。第二個(gè)線程的參數(shù)是“World”。
當(dāng)?shù)谝粋(gè)線程開(kāi)始執(zhí)行時(shí),它使用參數(shù)“Hello”執(zhí)行函數(shù)print_message_function。它在標(biāo)準(zhǔn)輸出中打印“Hello”,
然后結(jié)束對(duì)函數(shù)的調(diào)用。線程當(dāng)離開(kāi)它的初始化函數(shù)時(shí)就將終止,所以第一個(gè)線程在打印完“Hello”后終止。
當(dāng)?shù)诙䝼(gè)線程執(zhí)行時(shí),它打印“World”然后終止。但這個(gè)程序有兩個(gè)主要的缺陷。
首先也是最重要的是線程是同時(shí)執(zhí)行的。這樣就無(wú)法保證第一個(gè)線程先執(zhí)行打印語(yǔ)句。所以你很可能在屏幕上看到“World Hello”,
而不是“Hello World”。請(qǐng)注意對(duì)exit的調(diào)用是父線程在主程序中使用的。這樣,如果父線程在兩個(gè)子線程調(diào)用打印語(yǔ)句
之前調(diào)用exit,那么將不會(huì)有任何的打印輸出。這是因?yàn)閑xit函數(shù)將會(huì)退出進(jìn)程,同時(shí)釋放任務(wù),所以結(jié)束了所有的線程。
任何線程(不論是父線程或者子線程)調(diào)用exit 都會(huì)終止所有其他線程。如果希望線程分別終止,可以使用pthread_exit函數(shù)。
我們可以使用一個(gè)辦法彌補(bǔ)此缺陷。我們可以在父線程中插入一個(gè)延遲程序,給子線程足夠的時(shí)間完成打印的調(diào)用。同樣,
在調(diào)用第二個(gè)之前也插入一個(gè)延遲程序保證第一個(gè)線程在第二個(gè)線程執(zhí)行之前完成任務(wù)。
void print_message_function( void *ptr );
main ( )
{
pthread_t thread1, thread2;
char *message1 = "Hello”;
char *message2 = "Wo r l d " ;
pthread_create( &thread1, pthread_attr_default,
(void *) &print_message_function, (void *) message1);
sleep (10) ;
pthread_create(&thread2, pthread_attr_default,
(void *) &print_message_function, (void *) message2);
sleep ( 10 ) ;
exit (0) ;
}
void print_message_function( void *ptr )
{
char *message;
message = (char *) ptr;
printf("%s", message);
pthread_exit(0) ;
}
這樣是否達(dá)到了我們的要求了呢?不盡如此,因?yàn)橐揽繒r(shí)間的延遲執(zhí)行同步是不可靠的。這里遇到的情形和一個(gè)分布程序和
共享資源的情形一樣。共享的資源是標(biāo)準(zhǔn)的輸出設(shè)備,分布計(jì)算的程序是三個(gè)線程。
其實(shí)這里還有另外一個(gè)錯(cuò)誤。函數(shù)sleep和函數(shù)e x i t一樣和進(jìn)程有關(guān)。當(dāng)線程調(diào)用sleep時(shí),
整個(gè)的進(jìn)程都處于睡眠狀態(tài),也就是說(shuō),所有的三個(gè)線程都進(jìn)入睡眠狀態(tài)。這樣我們實(shí)際上沒(méi)有解決任何的問(wèn)題。
希望使一個(gè)線程睡眠的函數(shù)是pthread_delay_np。例如讓一個(gè)線程睡眠2秒鐘,用如下程序:
struct timespec delay;
delay.tv_sec = 2;
delay.tv_nsec = 0;
pthread_delay_np( &delay );
}
3. 線程同步
POSIX提供兩種線程同步的方法,mutex和條件變量。mutex是一種簡(jiǎn)單的加鎖的方法來(lái)控制對(duì)共享資源的存取。
我們可以創(chuàng)建一個(gè)讀/寫(xiě)程序,它們共用一個(gè)共享緩沖區(qū),使用mutex來(lái)控制對(duì)緩沖區(qū)的存取。
void reader_function(void);
void writer_function(void);
char buf f e r ;
int buffer_has_item = 0;
pthread_mutex_t mutex;
struct timespec delay;
main( )
{
pthread_t reader;
delay.tv_sec = 2;
delay.tv_nsec = 0;
pthread_mutex_init(&mutex, pthread_mutexattr_default);
pthread_create( &reader, pthread_attr_default, (void*)&reader_function,
N U L L ) ;
writer_function( )
void writer_function(void)
{
while( 1 )
{
pthread_mutex_lock( &mutex );
if ( buffer_has_item == 0 )
{
buffer = make_new_item();
buffer_has_item = 1;
}
pthread_mutex_unlock( &mutex );
pthread_delay_np( &delay );
}
}
void reader_function(void)
{
while( 1 )
{
pthread_mutex_lock( &mutex );
if ( buffer_has_item == 1)
{
consume_item( buffer );
buffer_has_item = 0;
}
pthread_mutex_unlock( &mutex );
pthread_delay_np( &delay );
}
}
在上面的程序中,我們假定緩沖區(qū)只能保存一條信息,這樣緩沖區(qū)只有兩個(gè)狀態(tài),有一條信息或者沒(méi)有信息。
使用延遲是為了避免一個(gè)線程永遠(yuǎn)占有mutex。
但mutex的缺點(diǎn)在于它只有兩個(gè)狀態(tài),鎖定和非鎖定。POSIX的條件變量通過(guò)允許線程阻塞和等待另一個(gè)線程的信號(hào)方法,
從而彌補(bǔ)了mutex的不足。當(dāng)接受到一個(gè)信號(hào)時(shí),阻塞線程將會(huì)被喚起,并試圖獲得相關(guān)的mutex的鎖。
4. 信號(hào)量
信號(hào)量是一個(gè)可以用來(lái)控制多個(gè)進(jìn)程存取共享資源的計(jì)數(shù)器。它經(jīng)常作為一種鎖定機(jī)制來(lái)防止當(dāng)一個(gè)進(jìn)程正在存取共享資源時(shí),
另一個(gè)進(jìn)程也存取同一資源。這里我會(huì)講的很詳細(xì),我可是花了很多時(shí)間去找這資料呀!!
下面先介紹一下信號(hào)量中涉及到的數(shù)據(jù)結(jié)構(gòu)。
1.內(nèi)核中的數(shù)據(jù)結(jié)構(gòu)semid_ds
和消息隊(duì)列一樣,系統(tǒng)內(nèi)核為內(nèi)核地址空間中的每一個(gè)信號(hào)量集都保存了一個(gè)內(nèi)部的數(shù)據(jù)結(jié)構(gòu)。數(shù)據(jù)結(jié)構(gòu)的原型是semid_ds。
它是在linux/sem.h中做如下定義的:
/*One semid data structure for each set of semaphores in the system.*/
structsemid_ds{
structipc_permsem_perm;/*permissions..seeipc.h*/
time_tsem_otime;/*last semop time*/
time_tsem_ctime;/*last change time*/
structsem*sem_base;/*ptr to first semaphore in array*/
structwait_queue*eventn;
structwait_queue*eventz;
structsem_undo*undo;/*undo requestson this array*/
ushortsem_nsems;/*no. of semaphores in array*/
};
sem_perm是在linux/ipc.h定義的數(shù)據(jù)結(jié)構(gòu)ipc_perm的一個(gè)實(shí)例。它保存有信號(hào)量集的存取權(quán)限的信息,
以及信號(hào)量集創(chuàng)建者的有關(guān)信息。
sem_otime最后一次semop()操作的時(shí)間。
sem_ctime最后一次改動(dòng)此數(shù)據(jù)結(jié)構(gòu)的時(shí)間。
sem_base指向數(shù)組中第一個(gè)信號(hào)量的指針。
sem_undo數(shù)組中沒(méi)有完成的請(qǐng)求的個(gè)數(shù)。
sem_nsems信號(hào)量集(數(shù)組)中的信號(hào)量的個(gè)數(shù)。
2.內(nèi)核中的數(shù)據(jù)結(jié)構(gòu)sem
在數(shù)據(jù)結(jié)構(gòu)semid_ds中包含一個(gè)指向信號(hào)量數(shù)組的指針。此數(shù)組中的每一個(gè)元素都是一個(gè)
數(shù)據(jù)結(jié)構(gòu)sem。它也是在linux/sem.h中定義的:
/*One semaphore structure for each semaphore in the system.*/
structsem{
shortsempid;/*pid of las toperation*/
ushortsemval;/*current value*/
ushortsemncnt;/*num procs awaiting increase in semval*/
ushortsemzcnt;/*num procs awaiting semval=0*/
};
sem_pid最后一個(gè)操作的PID(進(jìn)程ID)。
sem_semval信號(hào)量的當(dāng)前值。
sem_semncnt等待資源的進(jìn)程數(shù)目。
sem_semzcnt等待資源完全空閑的進(jìn)程數(shù)目。
以上說(shuō)的就是我們?cè)诔绦蚪?jīng)常用到的 (P/V)操作了
P 操作( 代表荷蘭語(yǔ) proberen 意思是嘗試) :
等待(wait)一個(gè)信號(hào)燈,該操作測(cè)試這個(gè)信號(hào)燈的值, 如果小于0||等于0, 那就等待(阻塞),
一但值變大就將它減些 1.
V 操作(代表荷蘭語(yǔ) verhogen 意思是增加):
掛出(post)一個(gè)信號(hào)燈, 該操作將信號(hào)燈的值加 1 .
關(guān)于P/V 操作先介紹到這了,下面在介紹信號(hào)量的一些方法:
semget()
我們可以使用系統(tǒng)調(diào)用semget()創(chuàng)建一個(gè)新的信號(hào)量集,或者存取一個(gè)已經(jīng)存在的信號(hào)量集:
系統(tǒng)調(diào)用:semget();
原型:intsemget(key_t key,int nsems,int semflg);
返回值:如果成功,則返回信號(hào)量集的IPC標(biāo)識(shí)符。如果失敗,則返回-1:errno=EACCESS(沒(méi)有權(quán)限)
EEXIST(信號(hào)量集已經(jīng)存在,無(wú)法創(chuàng)建)
EIDRM(信號(hào)量集已經(jīng)刪除)
ENOENT(信號(hào)量集不存在,同時(shí)沒(méi)有使用IPC_CREAT)
ENOMEM(沒(méi)有足夠的內(nèi)存創(chuàng)建新的信號(hào)量集)
ENOSPC(超出限制)
系統(tǒng)調(diào)用semget()的第一個(gè)參數(shù)是關(guān)鍵字值(一般是由系統(tǒng)調(diào)用ftok()返回的)。
系統(tǒng)內(nèi)核將此值和系統(tǒng)中存在的其他的信號(hào)量集的關(guān)鍵字值進(jìn)行比較。打開(kāi)和存取操作與參數(shù)semflg中的內(nèi)容相關(guān)。
IPC_CREAT如果信號(hào)量集在系統(tǒng)內(nèi)核中不存在,則創(chuàng)建信號(hào)量集。IPC_EXCL當(dāng)和IPC_CREAT一同使用時(shí),
如果信號(hào)量集已經(jīng)存在,則調(diào)用失敗。如果單獨(dú)使用IPC_CREAT,則semget()要么返回新創(chuàng)建的信號(hào)量集的標(biāo)識(shí)符,
要么返回系統(tǒng)中已經(jīng)存在的同樣的關(guān)鍵字值的信號(hào)量的標(biāo)識(shí)符。如果IPC_EXCL和IPC_CREAT一同使用,
則要么返回新創(chuàng)建的信號(hào)量集的標(biāo)識(shí)符,要么返回-1。IPC_EXCL單獨(dú)使用沒(méi)有意義。
參數(shù)nsems指出了一個(gè)新的信號(hào)量集中應(yīng)該創(chuàng)建的信號(hào)量的個(gè)數(shù)。
信號(hào)量集中最多的信號(hào)量的個(gè)數(shù)是在linux/sem.h中定義的:
#defineSEMMSL32/*
semop()
系統(tǒng)調(diào)用:semop();
調(diào)用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
返回值:0,如果成功。-1,如果失。篹rrno=E2BIG(nsops大于最大的ops數(shù)目)
EACCESS(權(quán)限不夠)
EAGAIN(使用了IPC_NOWAIT,但操作不能繼續(xù)進(jìn)行)
EFAULT(sops指向的地址無(wú)效)
EIDRM(信號(hào)量集已經(jīng)刪除)
EINTR(當(dāng)睡眠時(shí)接收到其他信號(hào))
EINVAL(信號(hào)量集不存在,或者semid無(wú)效)
ENOMEM(使用了SEM_UNDO,但無(wú)足夠的內(nèi)存創(chuàng)建所需的數(shù)據(jù)結(jié)構(gòu))
ERANGE(信號(hào)量值超出范圍)
第一個(gè)參數(shù)是關(guān)鍵字值。第二個(gè)參數(shù)是指向?qū)⒁僮鞯臄?shù)組的指針。第三個(gè)參數(shù)是數(shù)組中的操作的個(gè)數(shù)。
參數(shù)sops指向由sembuf組成的數(shù)組。此數(shù)組是在linux/sem.h中定義的:
/*semop systemcall takes an array of these*/
structsembuf{
ushortsem_num;/*semaphore index in array*/
shortsem_op;/*semaphore operation*/
shortsem_flg;/*operation flags*/
sem_num將要處理的信號(hào)量的個(gè)數(shù)。
sem_op要執(zhí)行的操作。
sem_flg操作標(biāo)志。
如果sem_op是負(fù)數(shù),那么信號(hào)量將減去它的值。這和信號(hào)量控制的資源有關(guān)。如果沒(méi)有使用IPC_NOWAIT,
那么調(diào)用進(jìn)程將進(jìn)入睡眠狀態(tài),直到信號(hào)量控制的資源可以使用為止。如果sem_op是正數(shù),則信號(hào)量加上它的值。
這也就是進(jìn)程釋放信號(hào)量控制的資源。最后,如果sem_op是0,那么調(diào)用進(jìn)程將調(diào)用sleep(),直到信號(hào)量的值為0。
這在一個(gè)進(jìn)程等待完全空閑的資源時(shí)使用。
semctl()
系統(tǒng)調(diào)用:semctl();
原型:int semctl(int semid,int semnum,int cmd,union semunarg);
返回值:如果成功,則為一個(gè)正數(shù)。
如果失敗,則為-1:errno=EACCESS(權(quán)限不夠)
EFAULT(arg指向的地址無(wú)效)
EIDRM(信號(hào)量集已經(jīng)刪除)
EINVAL(信號(hào)量集不存在,或者semid無(wú)效)
EPERM(EUID沒(méi)有cmd的權(quán)利)
ERANGE(信號(hào)量值超出范圍)
系統(tǒng)調(diào)用semctl用來(lái)執(zhí)行在信號(hào)量集上的控制操作。這和在消息隊(duì)列中的系統(tǒng)調(diào)用msgctl是十分相似的。
但這兩個(gè)系統(tǒng)調(diào)用的參數(shù)略有不同。因?yàn)樾盘?hào)量一般是作為一個(gè)信號(hào)量集使用的,而不是一個(gè)單獨(dú)的信號(hào)量。
所以在信號(hào)量集的操作中,不但要知道IPC關(guān)鍵字值,也要知道信號(hào)量集中的具體的信號(hào)量。這兩個(gè)系統(tǒng)調(diào)用都使用了參數(shù)cmd,
它用來(lái)指出要操作的具體命令。兩個(gè)系統(tǒng)調(diào)用中的最后一個(gè)參數(shù)也不一樣。在系統(tǒng)調(diào)用msgctl中,
最后一個(gè)參數(shù)是指向內(nèi)核中使用的數(shù)據(jù)結(jié)構(gòu)的指針。我們使用此數(shù)據(jù)結(jié)構(gòu)來(lái)取得有關(guān)消息隊(duì)列的一些信息,
以及設(shè)置或者改變隊(duì)列的存取權(quán)限和使用者。但在信號(hào)量中支持額外的可選的命令,這樣就要求有一個(gè)更為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
系統(tǒng)調(diào)用semctl()的第一個(gè)參數(shù)是關(guān)鍵字值。第二個(gè)參數(shù)是信號(hào)量數(shù)目。
參數(shù)cmd中可以使用的命令如下:
·IPC_STAT讀取一個(gè)信號(hào)量集的數(shù)據(jù)結(jié)構(gòu)semid_ds,并將其存儲(chǔ)在semun中的buf參數(shù)中。
·IPC_SET設(shè)置信號(hào)量集的數(shù)據(jù)結(jié)構(gòu)semid_ds中的元素ipc_perm,其值取自semun中的buf參數(shù)。
·IPC_RMID將信號(hào)量集從內(nèi)存中刪除。
·GETALL用于讀取信號(hào)量集中的所有信號(hào)量的值。
·GETNCNT返回正在等待資源的進(jìn)程數(shù)目。
·GETPID返回最后一個(gè)執(zhí)行semop操作的進(jìn)程的PID。
·GETVAL返回信號(hào)量集中的一個(gè)單個(gè)的信號(hào)量的值。
·GETZCNT返回這在等待完全空閑的資源的進(jìn)程數(shù)目。
·SETALL設(shè)置信號(hào)量集中的所有的信號(hào)量的值。
·SETVAL設(shè)置信號(hào)量集中的一個(gè)單獨(dú)的信號(hào)量的值。
參數(shù)arg代表一個(gè)semun的實(shí)例。semun是在linux/sem.h中定義的:
/*arg for semctl systemcalls.*/
unionsemun{
intval;/*value for SETVAL*/
structsemid_ds*buf;/*buffer for IPC_STAT&IPC_SET*/
ushort*array;/*array for GETALL&SETALL*/
structseminfo*__buf;/*buffer for IPC_INFO*/
void*__pad;
val當(dāng)執(zhí)行SETVAL命令時(shí)使用。buf在IPC_STAT/IPC_SET命令中使用。代表了內(nèi)核中使用的信號(hào)量的數(shù)據(jù)結(jié)構(gòu)。
array在使用GETALL/SETALL命令時(shí)使用的指針。
下面的程序返回信號(hào)量的值。當(dāng)使用GETVAL命令時(shí),調(diào)用中的最后一個(gè)參數(shù)被忽略:
intget_sem_val(intsid,intsemnum)
{
return(semctl(sid,semnum,GETVAL,0));
}
下面是一個(gè)實(shí)際應(yīng)用的例子:
#defineMAX_PRINTERS5
printer_usage()
{
int x;
for(x=0;x
注意系統(tǒng)調(diào)用semctl中的最后一個(gè)參數(shù)是一個(gè)聯(lián)合類型的副本,而不是一個(gè)指向聯(lián)合類型的指針。
本文就先介紹到這了, 因?yàn)檫@方面的應(yīng)用太廣了! 怕說(shuō)多了就會(huì)錯(cuò)!~~
參考文獻(xiàn):
UNIX 網(wǎng)絡(luò)編程 第2版 進(jìn)程間通迅 W.Richard Srevens 著
本文來(lái)自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u/8649/showart_89932.html |
|