前一篇文章概述了Linux 系統中信號量互斥編程,這篇文章正好是前一篇的姊妹篇----信號量同步。說它們是姊妹篇是由於它們都是利用了內核的信號量機制實現了進程間的通訊。由於二者所解決的問題不一樣,所以它們使用的場景就會有所區別。編程
信號量互斥主要解決的問題是:進程間須要同時訪問某種資源,可是它們對資源的操做會互相影響對方的操做結果,所以須要一種機制實現讓進程在訪問資源時能禁止其餘進程訪問相同的資源。而信號量同步則解決了另外一個經典問題:生產者和消費者之間的協同工做問題。app
首先描述一下生產者和消費者問題:進程A 負責生產產品(建立並寫入文件),進程B 負責消費產品(複製文件),理想的流程是當進程A 建立並寫好數據到文件之後,進程B就取走文件。可是兩個進程運行時機的不肯定每每讓這個流程出現混亂,即進程A的生產工做還未完成(如只建立了文件可是沒寫入數據),進程B 就複製了文件,致使進程B 獲得的是一個不完整的文件。事實上問題出現的緣由就是兩個進程間沒有一種同步的機制。ide
信號量的提出就解決了這個問題。信號量的實如今前一篇文章中有詳細介紹,這裏只是指出運用信號量同步進程與互斥之間的不一樣,而後給出一個實例說明。測試
下面是筆者實現代碼的思惟導圖:spa
與互斥不一樣的是,在給信號量賦初值時並非賦值爲1,而是賦值爲0,而且在生產者中並無獲取信號量,而在消費者中也沒有釋放信號量。這樣作是爲了使二者的運行次序不會影響最後的結果。code
能夠分析:若是生產者程序先運行,它會依次建立並寫入文件,假設此時消費者程序運行,可是此時信號量初值爲0,所以消費者程序被掛起。當生產者程序執行完,釋放信號量之後,消費者程序繼續運行,最後獲得正確的文件。blog
若是消費者程序先運行,它測試到信號量初值是0 ,所以直接被掛起,直到生產者程序運行完才繼續運行,可知這樣也可以獲得正確的文件。進程
須要注意的是,在上圖中的1.7 釋放信號量裏面,包含一個將初值置爲0 的操做,這樣是爲了在下一次再運行這兩個程序時,若是先運行消費者,初值仍然是0。ip
下面是筆者的測試代碼:資源
生產者代碼:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/sem.h> int main(int argc, char **argv) { int fd = 0; key_t key; int semid; struct sembuf ops; //建立信號量集合 key = ftok("/home/application/semapthore",1); semid=semget(key,1,IPC_CREAT); //將初值置爲0 semctl(semid,0,SETVAL,0); //建立文件 fd = open("./product.txt",O_RDWR|O_CREAT,0755); //休息 sleep(20); //寫入數據 write(fd,"Product is finished!",21); //關閉文件 close(fd); //釋放信號量 ops.sem_num=0; ops.sem_op=1; ops.sem_flg = SEM_UNDO; semop(semid,&ops,1); semctl(semid,0,SETVAL,0); return 0; }
消費者代碼;
#include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int main(int argc,char **argv) { key_t key; int semid; struct sembuf ops; //打開信號量集合 key = ftok("/home/application/semapthore",1); semid=semget(key,1,IPC_CREAT); //獲取信號量 ops.sem_num = 0; ops.sem_op = -1; ops.sem_flg = SEM_UNDO; semop(semid,&ops,1); //消費文件 system("cp ./product.txt ./comsum/"); return 0; }