A. linux信號量
信號量是包含一個非負整數型的變數,並且帶有兩個原子操作wait和signal。Wait還可以被稱為down、P或lock,signal還可以被稱為up、V、unlock或post。在UNIX的API中(POSIX標准)用的是wait和post。
對於wait操作,如果信號量的非負整形變數S大於0,wait就將其減1,如果S等於0,wait就將調用線程阻塞;對於post操作,如果有線程在信號量上阻塞(此時S等於0),post就會解除對某個等待線程的阻塞,使其從wait中返回,如果沒有線程阻塞在信號量上,post就將S加1.
由此可見,S可以被理解為一種資源的數量,信號量即是通過控制這種資源的分配來實現互斥和同步的。如果把S設為1,那麼信號量即可使多線程並發運行。另外,信號量不僅允許使用者申請和釋放資源,而且還允許使用者創造資源,這就賦予了信號量實現同步的功能。可見信號量的功能要比互斥量豐富許多。
POSIX信號量是一個sem_t類型的變數,但POSIX有兩種信號量的實現機制: 無名信號量 和 命名信號量 。無名信號量只可以在共享內存的情況下,比如實現進程中各個線程之間的互斥和同步,因此無名信號量也被稱作基於內存的信號量;命名信號量通常用於不共享內存的情況下,比如進程間通信。
同時,在創建信號量時,根據信號量取值的不同,POSIX信號量還可以分為:
下面是POSIX信號量函數介面:
信號量的函數都以sem_開頭,線程中使用的基本信號函數有4個,他們都聲明在頭文件semaphore.h中,該頭文件定義了用於信號量操作的sem_t類型:
【sem_init函數】:
該函數用於創建信號量,原型如下:
該函數初始化由sem指向的信號對象,設置它的共享選項,並給它一個初始的整數值。pshared控制信號量的類型,如果其值為0,就表示信號量是當前進程的局部信號量,否則信號量就可以在多個進程間共享,value為sem的初始值。
該函數調用成功返回0,失敗返回-1。
【sem_destroy函數】:
該函數用於對用完的信號量進行清理,其原型如下:
成功返回0,失敗返回-1。
【sem_wait函數】:
該函數用於以原子操作的方式將信號量的值減1。原子操作就是,如果兩個線程企圖同時給一個信號量加1或減1,它們之間不會互相干擾。其原型如下:
sem指向的對象是sem_init調用初始化的信號量。調用成功返回0,失敗返回-1。
sem_trywait()則是sem_wait()的非阻塞版本,當條件不滿足時(信號量為0時),該函數直接返回EAGAIN錯誤而不會阻塞等待。
sem_timedwait()功能與sem_wait()類似,只是在指定的abs_timeout時間內等待,超過時間則直接返回ETIMEDOUT錯誤。
【sem_post函數】:
該函數用於以原子操作的方式將信號量的值加1,其原型如下:
與sem_wait一樣,sem指向的對象是由sem_init調用初始化的信號量。調用成功時返回0,失敗返回-1。
【sem_getvalue函數】:
該函數返回當前信號量的值,通過restrict輸出參數返回。如果當前信號量已經上鎖(即同步對象不可用),那麼返回值為0,或為負數,其絕對值就是等待該信號量解鎖的線程數。
【實例1】:
【實例2】:
之所以稱為命名信號量,是因為它有一個名字、一個用戶ID、一個組ID和許可權。這些是提供給不共享內存的那些進程使用命名信號量的介面。命名信號量的名字是一個遵守路徑名構造規則的字元串。
【sem_open函數】:
該函數用於創建或打開一個命名信號量,其原型如下:
參數name是一個標識信號量的字元串。參數oflag用來確定是創建信號量還是連接已有的信號量。
oflag的參數可以為0,O_CREAT或O_EXCL:如果為0,表示打開一個已存在的信號量;如果為O_CREAT,表示如果信號量不存在就創建一個信號量,如果存在則打開被返回,此時mode和value都需要指定;如果為O_CREAT|O_EXCL,表示如果信號量存在則返回錯誤。
mode參數用於創建信號量時指定信號量的許可權位,和open函數一樣,包括:S_IRUSR、S_IWUSR、S_IRGRP、S_IWGRP、S_IROTH、S_IWOTH。
value表示創建信號量時,信號量的初始值。
【sem_close函數】:
該函數用於關閉命名信號量:
單個程序可以用sem_close函數關閉命名信號量,但是這樣做並不能將信號量從系統中刪除,因為命名信號量在單個程序執行之外是具有持久性的。當進程調用_exit、exit、exec或從main返回時,進程打開的命名信號量同樣會被關閉。
【sem_unlink函數】:
sem_unlink函數用於在所有進程關閉了命名信號量之後,將信號量從系統中刪除:
【信號量操作函數】:
與無名信號量一樣,操作信號量的函數如下:
命名信號量是隨內核持續的。當命名信號量創建後,即使當前沒有進程打開某個信號量,它的值依然保持,直到內核重新自舉或調用sem_unlink()刪除該信號量。
無名信號量的持續性要根據信號量在內存中的位置確定:
很多時候信號量、互斥量和條件變數都可以在某種應用中使用,那這三者的差異有哪些呢?下面列出了這三者之間的差異:
B. linux 信號量是什麼怎麼用
Linux信號量(semaphore)是一種互斥機制。即對某個互斥資源的訪問會收到信號量的保護,在訪問之前需要獲得信號量。
在操作完共享資源後,需釋放信號量,以便另外的進程來獲得資源。獲得和釋放應該成對出現。
獲得信號量集,需要注意的是,獲得的是一個集合,而不是一個單一的信號量。
#include
#include
#include
1: int semget(key_t key,int nsems,int semflg);
key:系統根據這個值來獲取信號量集。
nsems:此信號集包括幾個信號量。
semflg:創建此信號量的屬性。 (IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)
成功則返回該信號量集的ID。
註:
既指定IPC_CREAT又指定IPC_EXCL時,如果系統中該信號量集已經存在,則馬上返回。
如果需要獲得存在的信號量,則將此參數置0.
2: int semctl(int semid,int senum,int cmd....)
semid:信號量ID。
senum:對信號量集中的第幾個信號量進行控制。(從0開始)
cmd:需要進行的操作。(SETVAL是其中的一個)。
根據cmd的不同可能存在第四個參數,cmd=SETVAL時,表示同時信號量可以被獲得幾次,如第四個參數
num=1表示只能被獲得一次,既被信號量保護的資源只能同時被一個程序使用。
該系統調用,是在對信號量初始化時用的。
-3: 「3」前面加了"-"表示當需要使用互斥資源時應該做這步。
int semop(int semid,struct sembuf *sem,int num_elements);
struct sembuf {
unsigned short sem_num; //該信號量集中的第幾個信號量。
int sem_op;//需要獲得還是釋放信號量
int sem_flg;//相關動作
};
num_elements:需要對該信號量集中的多少個信號量進行處理。
獲得信號量時,將sembuf結構提初始化為:
sem_num = 0; //該信號量集中的首個信號量
sem_op = -1; //獲得信號量
sem_flag = IPC_NOWAIT; //如果不能獲得信號量,馬上返回。
semop(semid,_sem,1);
同理釋放信號量時,將sem_op設為1.
以上是對信號量的簡單處理
C. 濡備綍鍦↙inux涓閫氳繃semget鍜宻emctl鍑芥暟鍒嗛厤騫墮噴鏀句俊鍙烽噺錛
Linux 緋葷粺涓錛屼俊鍙烽噺鐨勭$悊閫氳繃 semget 鍜 semctl 榪欎袱涓緋葷粺璋冪敤鏉ュ畬鎴愶紝瀹冧滑鐨勪綔鐢ㄧ被浼間簬 shmget 鍜 shmctl 瀵瑰叡浜鍐呭瓨鐨勫勭悊銆傝佷嬌鐢ㄤ俊鍙烽噺錛屼綘闇瑕侀栧厛璋冪敤 semget 鍑芥暟錛屼紶鍏ュ弬鏁板寘鎷淇″彿閲忕粍鐨勯敭鍊箋佷俊鍙烽噺鐨勬暟閲忎互鍙婃潈闄愭爣璇嗐傞敭鍊肩敤浜庡敮涓鏍囪瘑淇″彿閲忕粍錛屽嵆浣胯繘紼嬮鍑猴紝淇″彿閲忎篃浼氬湪緋葷粺涓鎸佷箙瀛樺湪銆傝幏鍙栧凡瀛樺湪鐨勪俊鍙烽噺鏃訛紝鍙浠ヤ紶鍏0浣滀負緇勫歸噺銆
淇″彿閲忕殑鐢熷懡鍛ㄦ湡闇瑕佹墜鍔ㄧ$悊錛屽綋鏈鍚庝竴涓浣跨敤淇″彿閲忕殑榪涚▼閫鍑烘椂錛岄渶瑕佽皟鐢 semctl 鍑芥暟鏉ュ垹闄や俊鍙烽噺緇勩傝繖涓鍑芥暟闇瑕佸洓涓鍙傛暟錛氫俊鍙烽噺緇勬爣璇嗙︺佽佹搷浣滅殑淇″彿閲忕紪鍙鳳紙鍦ㄨ繖涓渚嬪瓙涓鏄1錛夈佸父閲 IPC_RMID 鍜屼竴涓 union semun 綾誨瀷鐨勭粨鏋勪綋錛堝疄闄呮搷浣滀腑蹇界暐錛夈傚垹闄ゆ搷浣滆佹眰璋冪敤鑰呬笌淇″彿閲忕粍鍒涘緩鑰呮潈闄愮浉鍚岋紝鎴栬呮嫢鏈 root 鏉冮檺銆備笌 shmget 涓嶅悓錛屽垹闄や俊鍙烽噺緇勪細絝嬪嵆閲婃斁緋葷粺璧勬簮銆
鍦ㄤ唬鐮佸眰闈錛屽備唬鐮 5.2錛坰em_all_deall.c錛夋墍紺猴紝鏈変袱涓鍏抽敭鍑芥暟錛氫竴涓鐢ㄤ簬鍒嗛厤浜屽厓淇″彿閲忥紙binary_semaphore_allocation錛夛紝閫氳繃 semget 鍑芥暟鑾峰彇鎴栧壋寤猴紱鍙︿竴涓鐢ㄤ簬閲婃斁浜屽厓淇″彿閲忥紙binary_semaphore_deallocate錛夛紝浣跨敤 semctl 鍑芥暟榪涜屽垹闄ゆ搷浣滐紝紜淇濊祫婧愮殑姝g『閲婃斁銆
鍒嗛厤浜屽厓淇″彿閲忥細 int binary_semaphore_allocation (key_t key, int sem_flags)錛岃繑鍥 semget 鐨勭粨鏋滐紝濡傛灉闇瑕佸垯鍒涘緩淇″彿閲忋
閲婃斁浜屽厓淇″彿閲忥細 int binary_semaphore_deallocate (int semid)錛岃皟鐢 semctl 鍑芥暟鍒犻櫎淇″彿閲忥紝鍙傛暟鍖呮嫭淇″彿閲忕粍鏍囪瘑絎﹀拰甯擱噺 IPC_RMID銆
Linux 鎻愪緵鐨勫悇縐嶇郴緇熻皟鐢ㄦ潵瀹炵幇涓涓鍏鋒湁涓ょ嶇姸鎬佺殑淇″彿閲忥紙binary semaphore錛夈
D. c語言實例,linux線程同步的信號量方式 謝謝
這么高的懸賞,實例放後面。信號量(sem),如同進程一樣,線程也可以通過信號量來實現通信,雖然是輕量級的。信號量函數的名字都以"sem_"打頭。線程使用的基本信號量函數有四個。
信號量初始化。
intsem_init(sem_t*sem,intpshared,unsignedintvalue);
這是對由sem指定的信號量進行初始化,設置好它的共享選項(linux只支持為0,即表示它是當前進程的局部信號量),然後給它一個初始值VALUE。
等待信號量。給信號量減1,然後等待直到信號量的值大於0。
intsem_wait(sem_t*sem);
釋放信號量。信號量值加1。並通知其他等待線程。
intsem_post(sem_t*sem);
銷毀信號量。我們用完信號量後都它進行清理。歸還佔有的一切資源。
intsem_destroy(sem_t*sem);
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#include<errno.h>
#definereturn_if_fail(p)if((p)==0){printf("[%s]:funcerror!/n",__func__);return;}
typedefstruct_PrivInfo
{
sem_ts1;
sem_ts2;
time_tend_time;
}PrivInfo;
staticvoidinfo_init(PrivInfo*thiz);
staticvoidinfo_destroy(PrivInfo*thiz);
staticvoid*pthread_func_1(PrivInfo*thiz);
staticvoid*pthread_func_2(PrivInfo*thiz);
intmain(intargc,char**argv)
{
pthread_tpt_1=0;
pthread_tpt_2=0;
intret=0;
PrivInfo*thiz=NULL;
thiz=(PrivInfo*)malloc(sizeof(PrivInfo));
if(thiz==NULL)
{
printf("[%s]:Failedtomallocpriv./n");
return-1;
}
info_init(thiz);
ret=pthread_create(&pt_1,NULL,(void*)pthread_func_1,thiz);
if(ret!=0)
{
perror("pthread_1_create:");
}
ret=pthread_create(&pt_2,NULL,(void*)pthread_func_2,thiz);
if(ret!=0)
{
perror("pthread_2_create:");
}
pthread_join(pt_1,NULL);
pthread_join(pt_2,NULL);
info_destroy(thiz);
return0;
}
staticvoidinfo_init(PrivInfo*thiz)
{
return_if_fail(thiz!=NULL);
thiz->end_time=time(NULL)+10;
sem_init(&thiz->s1,0,1);
sem_init(&thiz->s2,0,0);
return;
}
staticvoidinfo_destroy(PrivInfo*thiz)
{
return_if_fail(thiz!=NULL);
sem_destroy(&thiz->s1);
sem_destroy(&thiz->s2);
free(thiz);
thiz=NULL;
return;
}
staticvoid*pthread_func_1(PrivInfo*thiz)
{
return_if_fail(thiz!=NULL);
while(time(NULL)<thiz->end_time)
{
sem_wait(&thiz->s2);
printf("pthread1:pthread1getthelock./n");
sem_post(&thiz->s1);
printf("pthread1:pthread1unlock/n");
sleep(1);
}
return;
}
staticvoid*pthread_func_2(PrivInfo*thiz)
{
return_if_fail(thiz!=NULL);
while(time(NULL)<thiz->end_time)
{
sem_wait(&thiz->s1);
printf("pthread2:pthread2gettheunlock./n");
sem_post(&thiz->s2);
printf("pthread2:pthread2unlock./n");
sleep(1);
}
return;
}