這篇“l(fā)inux可不可以創(chuàng)建多個(gè)進(jìn)程”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“l(fā)inux可不可以創(chuàng)建多個(gè)進(jìn)程”文章吧。
專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)羅江免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千余家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
linux可以創(chuàng)建多個(gè)進(jìn)程。linux支持多進(jìn)程,可以同時(shí)處理多個(gè)任務(wù),實(shí)現(xiàn)系統(tǒng)資源的最大利用。linux進(jìn)程間的通信方式:1、利用無(wú)名管道pipe;2、利用有名管道(FIFO);3、利用信號(hào)single;4、利用共享內(nèi)存;5、利用消息隊(duì)列;6、利用信號(hào)量。
linux可以創(chuàng)建多個(gè)進(jìn)程。
linux 支持多進(jìn)程。多進(jìn)程系統(tǒng)的一個(gè)好處,就是可以同時(shí)處理多個(gè)任務(wù),實(shí)現(xiàn)系統(tǒng)資源的最大利用。
1.1 概述
linux中把正在運(yùn)行的程序稱作進(jìn)程。
程序:靜態(tài)的概念,它是一個(gè)編譯好的二進(jìn)制文件
進(jìn)程:動(dòng)態(tài)的概念,當(dāng)程序運(yùn)行的時(shí)候,系統(tǒng)會(huì)自動(dòng)運(yùn)行一個(gè)對(duì)應(yīng)進(jìn)程
進(jìn)程包含了進(jìn)程控制塊(PCB),代碼段,數(shù)據(jù)段三個(gè)部分
進(jìn)程控制塊:在linux中是用一個(gè)結(jié)構(gòu)體來(lái)表示的,記錄進(jìn)程的狀態(tài)信息
僵尸進(jìn)程:父進(jìn)程優(yōu)先于子進(jìn)程退出
如果你創(chuàng)建了子進(jìn)程,但是在父進(jìn)程中沒(méi)有回收該子進(jìn)程的資源,那么該子進(jìn)程就會(huì)變成僵尸進(jìn)程,僵尸進(jìn)程最終會(huì)由系統(tǒng)中一個(gè)叫做INIT的進(jìn)程回收。
init進(jìn)程(1號(hào)進(jìn)程)是系統(tǒng)啟動(dòng)的時(shí)候運(yùn)行的第一個(gè)進(jìn)程,是所有進(jìn)程的祖進(jìn)程。
top查看動(dòng)態(tài)的進(jìn)程信息
ps -ef查看進(jìn)程的詳細(xì)信息
pstree以樹狀的形式顯示進(jìn)程的信息
bg將掛起的進(jìn)程放到后臺(tái)運(yùn)行
1.2 進(jìn)程運(yùn)行狀態(tài)
執(zhí)行態(tài)( RUNNING):進(jìn)程正在占有CPU。
就緒態(tài)( RUNNING):進(jìn)程處于等待隊(duì)列中等待調(diào)度。
淺睡眠( INTERRUPTABLE):此時(shí)進(jìn)程在等待一個(gè)事件的發(fā)生或某種系統(tǒng)資源,可響應(yīng)信號(hào)。
深睡眠( UNINTERRUPTABLE): 此時(shí)進(jìn)程在等待一個(gè)事件的發(fā)生或某種系統(tǒng)資源, 無(wú)法響應(yīng)信號(hào)。
停止態(tài)( STOPPED): 此時(shí)進(jìn)程被暫停。
僵尸態(tài)( ZOMBIE): 此時(shí)進(jìn)程不能被調(diào)度,但是PCB未被釋放。
死亡態(tài)( DEAD): 這是一個(gè)已終止的進(jìn)程,且PCB將會(huì)被釋放
內(nèi)核態(tài):也叫內(nèi)核空間,是內(nèi)核進(jìn)程/線程所在的區(qū)域。主要負(fù)責(zé)運(yùn)行系統(tǒng)、硬件交互。
用戶態(tài):也叫用戶空間,是用戶進(jìn)程/線程所在的區(qū)域。主要用于執(zhí)行用戶程序。
1、區(qū)別
內(nèi)核態(tài):運(yùn)行的代碼不受任何限制,CPU可以執(zhí)行任何指令。
用戶態(tài):不能調(diào)度CPU,不能直接訪問(wèn)硬件。運(yùn)行的代碼需要受到CPU的很多檢查,不能直接訪問(wèn)內(nèi)核數(shù)據(jù)和程序,也就是不可以像內(nèi)核態(tài)線程一樣訪問(wèn)任何有效地址。
操作系統(tǒng)在執(zhí)行用戶程序時(shí),主要工作在用戶態(tài),只有在其執(zhí)行沒(méi)有權(quán)限完成的任務(wù)時(shí)才會(huì)切換到內(nèi)核態(tài)。
2、區(qū)分用戶態(tài)和內(nèi)核態(tài)原因
保護(hù)機(jī)制,防止用戶進(jìn)程誤操作或者是惡意破壞系統(tǒng)
保證資源的集中管理,減少資源的使用沖突。
3、用戶態(tài)切換到內(nèi)核態(tài)方式
(1)系統(tǒng)調(diào)用(主動(dòng))
系統(tǒng)調(diào)用(system call)是操作系統(tǒng)提供給用戶進(jìn)程請(qǐng)求操作系統(tǒng)做一些特權(quán)操作的接口,即為用戶進(jìn)程提供服務(wù)的窗口。在Linux下可以通過(guò)man syscalls命令查看Linux提供的所有系統(tǒng)調(diào)用API接口。
由于用戶態(tài)無(wú)法完成某些任務(wù),用戶態(tài)會(huì)請(qǐng)求切換到內(nèi)核態(tài),內(nèi)核態(tài)通過(guò)為用戶專門開放的中斷完成切換。
(2)外圍設(shè)備中斷(被動(dòng))
外圍設(shè)備發(fā)出中斷信號(hào),當(dāng)中斷發(fā)生后,當(dāng)前運(yùn)行的進(jìn)程暫停運(yùn)行,并由操作系統(tǒng)內(nèi)核對(duì)中斷進(jìn)程處理,如果中斷之前CPU執(zhí)行的是用戶態(tài)程序,就相當(dāng)于從用戶態(tài)向內(nèi)核態(tài)的切換。
中斷用于保證CPU控制權(quán)交給操作系統(tǒng),從而讓操作系統(tǒng)可以執(zhí)行某些操作。
(3)異常(被動(dòng))
在執(zhí)行用戶程序時(shí)出現(xiàn)某些不可知的異常,會(huì)從用戶程序切換到內(nèi)核中處理該異常的程序,也就是切換到了內(nèi)核態(tài)。
1.3 進(jìn)程接口函數(shù)
1、fork()、vfork()
(1)新建的進(jìn)程稱作子進(jìn)程,它復(fù)制了父進(jìn)程的所有資源(只在創(chuàng)建的那個(gè)時(shí)間復(fù)制一次,以后全局變量值是不同),父子進(jìn)程誰(shuí)先誰(shuí)后是不確定。
#include
(2)**vfork()**子進(jìn)程共享了父進(jìn)程的所有資源,它一定是子進(jìn)程先運(yùn)行,然后才是父進(jìn)程運(yùn)行(即使你加上sleep()人為去干擾也是沒(méi)有用的)
(3)注意
子進(jìn)程中使用了exit()跟沒(méi)有使用結(jié)果完全不一樣
父子進(jìn)程中是否使用sleep()來(lái)讓出cpu時(shí)間片也是不一樣的
父進(jìn)程中是否使用wait(),waitpid()結(jié)果也是不一樣的
(4)進(jìn)程切換執(zhí)行
1、exit()、_exit()
#include
1、wait()
#include
2、 waitpid()
pid_t waitpid(pid_t pid, int *stat_loc, int options); 回收子進(jìn)程/進(jìn)程組
參數(shù): pid ----》你指定要回收的那個(gè)子進(jìn)程的id
<-1 等待進(jìn)程組號(hào)為-pid中的某個(gè)子進(jìn)程退出
-1 等待任意一個(gè)子進(jìn)程
==0 等待本進(jìn)程組中的某個(gè)子進(jìn)程退出
> 0 等待PID為pid的進(jìn)程
stat_loc-----》存放子進(jìn)程退出狀態(tài)(可為NULL)
options ----》一般設(shè)置為0
WNOHANG 當(dāng)沒(méi)有子進(jìn)程時(shí)立即返回
WUNTRACED 當(dāng)有子進(jìn)程被暫停時(shí)立即返回
WCONTINUED 當(dāng)有子進(jìn)程收到SIGCONT立即返回
返回值:-1 執(zhí)行失敗
> 0 成功 返回值為被回收的進(jìn)程的PID
0 指定了WNOHANG,且沒(méi)有已退出的子進(jìn)程
(1)獲取自己的id getpid()
#include
不管是進(jìn)程間的通信,還是線程間的通信。無(wú)非都是為了解決一個(gè)問(wèn)題:就是共享資源的分配(協(xié)調(diào)不同的進(jìn)程/線程對(duì)于共享的資源的訪問(wèn))
2.1 進(jìn)程間的通信方式
1、傳統(tǒng)的進(jìn)程間通信方式
無(wú)名管道
有名管道
信號(hào)
2、System V IPC對(duì)象
共享內(nèi)存
消息隊(duì)列
信號(hào)量
3、BSD
網(wǎng)絡(luò)套接字(socket)
1、特點(diǎn):最原始的進(jìn)程間的通信方式
它只能在具有親緣關(guān)系的進(jìn)程間通信(父子進(jìn)程,兄弟進(jìn)程);
它沒(méi)有名字(是存在的);
可以在linux和windows之間的共享中創(chuàng)建(根本就不會(huì)生成管道文件),但是有名管道就不可以了(生成管道文件);
半雙工通信。
2、無(wú)名管道的使用
(1)創(chuàng)建pipe()
#include
(2)pipe信息收發(fā)
myid = fork(); //創(chuàng)建子進(jìn)程
if(myid == 0)
{
write(fd[1],"dad,thanks!",20); //子進(jìn)程向父進(jìn)程發(fā)送消息
close(fd[1]);
close(fd[0]);
exit(0);
}
else if(myid > 0)
{
read(fd[0],buf,20); //父進(jìn)程阻塞接受子進(jìn)程消息
printf("buf is:%s\n",buf);
close(fd[1]);
close(fd[0]);
}
1、特點(diǎn):隨便兩個(gè)進(jìn)程之間都行
不能在linux和windows之間的共享中創(chuàng)建;
保證寫入的原子性(原子性:要么不做,要做就一口氣做完不受外界的干擾);
有名管道不能夠覆蓋著創(chuàng)建(一般代碼中使用access()函數(shù)來(lái)判斷是否存在,如果已經(jīng)存在同名的管道,就不能再次創(chuàng)建);
使用完畢記得關(guān)閉;
當(dāng)管道以只讀的方式打開,會(huì)阻塞,直到有另外一個(gè)進(jìn)程以只寫的方式打開這個(gè)管道,那么就不阻塞了;如果是以可讀寫的方式打開,就不會(huì)阻塞了。
全雙工通信,半雙道。
2、有名管道的使用
(1)創(chuàng)建mkfifo()
#include
(2)FIFO進(jìn)程信息收發(fā)
fifo_read.c :-----------》
#define FIFO1 "myfifo1"
#define FIFO2 "myfifo2"
int main(void) {
int my_fd,fd1,fd2;
char r_buff[30];
char w_buff[30];
bzero(r_buff,30);
if(access(FIFO1,F_OK)==-1) {
my_fd = mkfifo(FIFO1,0664); //創(chuàng)建管道1
if(my_fd == -1) {
perror("failed!\n");
return -1;
}
}
if(access(FIFO2,F_OK)==-1) {
my_fd = mkfifo(FIFO2,0664); //創(chuàng)建管道2
if(my_fd == -1) {
perror("failed!\n");
return -1;
}
}
fd1 = open(FIFO1,O_RDONLY); //只讀打開管道1,獲取管道文件描述符
if(fd1==-1) {
printf("open fifo1 file failed!\n");
exit(0);
}
fd2 = open(FIFO2,O_WRONLY); //只寫打開管道2,獲取管道文件描述符
if(fd2==-1) {
printf("open fifo2 file failed!\n");
exit(0);
}
while(1) {
bzero(r_buff,30);
read(fd1,r_buff,sizeof(r_buff)); //讀取管道1的消息
printf("client receive message is: %s\n",r_buff);
printf("client please input a message!\n");
fgets(w_buff,30,stdin);
write(fd2,w_buff,30); //發(fā)送信息給管道2
}
close(fd2);
close(fd1);
return 0;
}
fifo_write.c :-----------》
#define FIFO1 "myfifo1"
#define FIFO2 "myfifo2"
int main(void)
{
int my_fd,fd1,fd2;
char w_buff[30];
char r_buff[30];
bzero(w_buff,30);
if(access(FIFO1,F_OK)==-1) {
my_fd = mkfifo(FIFO1,0664);
if(my_fd == -1) {
perror("failed!\n");
return -1;
}
}
if(access(FIFO2,F_OK)==-1) {
my_fd = mkfifo(FIFO2,0664);
if(my_fd == -1) {
perror("failed!\n");
return -1;
}
}
fd1 = open(FIFO1,O_WRONLY);
if(fd1==-1) {
printf("open fifo1 file failed!\n");
exit(0);
}
fd2 = open(FIFO2,O_RDONLY);
if(fd2==-1) {
printf("open fifo2 file failed!\n");
exit(0);
}
while(1) {
bzero(w_buff,30);
printf("server please input a message!\n");
fgets(w_buff,30,stdin);
write(fd1,w_buff,strlen(w_buff)); //寫入消息到管道1文件
read(fd2,r_buff,30); //讀取信息從管道2
printf("server receive message is:%s\n",r_buff);
}
close(fd1);
close(fd2);
return 0;
}
程序(進(jìn)程)在運(yùn)行過(guò)程中,外界不定時(shí)會(huì)發(fā)信號(hào)給該程序,這個(gè)時(shí)候該程序面臨著兩種選擇:
不理它(阻塞/忽略)
阻塞:是指將信號(hào)掛起,等到程序運(yùn)行完了再去響應(yīng)
忽略:舍棄這個(gè)信號(hào)
響應(yīng)它
1、linux當(dāng)中有哪些信號(hào):kill -l 查看
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
(1)1到31號(hào)信號(hào)稱作非實(shí)時(shí)信號(hào):不支持隊(duì)列(如果同時(shí)來(lái)了多個(gè)信號(hào),響應(yīng)是沒(méi)有規(guī)律)
(2)用戶自定義的信號(hào) 10) SIGUSR1 12) SIGUSR2
(3) 34到64號(hào)信號(hào)叫做實(shí)時(shí)信號(hào):支持隊(duì)列,是linux系統(tǒng)中后面添加進(jìn)來(lái)的信號(hào)
信號(hào)類似于中斷: 硬件 軟件
以上信號(hào)有兩個(gè)很特殊:SIGKILL,SIGSTOP不能夠被忽略,也不能被阻塞
2、信號(hào)相關(guān)的操作函數(shù)
(1)發(fā)送信號(hào)kill()
#include
(2)信號(hào)的捕捉 signal()
#include
(3)等待信號(hào) pause()
#include
(4)信號(hào)的阻塞
每個(gè)進(jìn)程都有屬于它自己的一個(gè)信號(hào)掩碼(也就是該進(jìn)程在運(yùn)行的過(guò)程中會(huì)阻塞掉的那些信號(hào)就被稱作信號(hào)掩碼)。
關(guān)于信號(hào)掩碼操作的一系列函數(shù):
#include
(5)配置信號(hào)掩碼 sigprocmask()—阻塞或解除阻塞信號(hào)
#include
(6)捕捉指定信號(hào)并獲取信號(hào)攜帶信息sigaction()
#include
查看共享內(nèi)存: ipcs -m
刪除共享內(nèi)存: ipcrm -m 共享內(nèi)存的id
SYSTEM-V ipc通信方式:共享內(nèi)存、信號(hào)量、消息隊(duì)列。
1、共享內(nèi)存特點(diǎn):跟mmap()思想上有些類似
在進(jìn)程通信方式中共享內(nèi)存是效率最高的,進(jìn)程可以直接讀寫內(nèi)存,而不需要任何數(shù)據(jù)的拷貝;
如果代碼不人為地刪除共享共享內(nèi)存,那么程序退出的時(shí)候它還在;
多個(gè)進(jìn)程共享一段內(nèi)存,因此也需要依靠某種同步機(jī)制,如互斥鎖和信號(hào)量等
2、共享內(nèi)存對(duì)應(yīng)的一系列操作函數(shù)
(1)創(chuàng)建共享內(nèi)存:shmget()
#include
(2) 映射共享內(nèi)存到用戶空間 shmat()
#include
(3)解除映射:shmdt()
#include
(4)刪除共享內(nèi)存:shmctl()
#include
3、共享內(nèi)存簡(jiǎn)單示例
shm_write.c :----------》
int main() {
int shmid;
int *p;
// 創(chuàng)建共享內(nèi)存
shmid = shmget((key_t)456,1024,IPC_CREAT|IPC_EXCL|0666);
if((shmid == -1)&&(errno == EEXIST)) {
shmid = shmget((key_t)456,1024,0666);
}
// 映射共享內(nèi)存到進(jìn)程
p = (int *)shmat(shmid,NULL,0);
*p = 10;
// 解除映射
shmdt(p);
// 刪除內(nèi)存
//shmctl(shmid,IPC_RMID,NULL);
return 0;
}
shm_read.c :----------》
int main() {
int shmid;
int *p;
// 創(chuàng)建共享內(nèi)存
shmid = shmget((key_t)456,1024,IPC_CREAT|IPC_EXCL|0666);
if((shmid == -1)&&(errno == EEXIST)) {
shmid = shmget((key_t)456,1024,0666);
}
// 映射共享內(nèi)存到進(jìn)程
p = (int *)shmat(shmid,NULL,0);
printf("p is :%d\n",*p);
// 解除映射
shmdt(p);
// 刪除內(nèi)存
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
消息隊(duì)列就是一個(gè)消息的列表。用戶可以在消息隊(duì)列中添加消息、讀取消息等。
消息隊(duì)列由消息隊(duì)列ID來(lái)唯一標(biāo)識(shí)
消息隊(duì)列可以按照類型來(lái)發(fā)送/接收消息
消息隊(duì)列的操作包括創(chuàng)建或打開消息隊(duì)列、添加消息、讀取消息和控制消息隊(duì)列
1、消息隊(duì)列的特點(diǎn)
寫入消息隊(duì)列的信息,在編寫程序的時(shí)候會(huì)人為的去設(shè)置消息的類型(用整數(shù)來(lái)表示),目的是為了其它進(jìn)程在讀取信息的時(shí)候能夠準(zhǔn)確地通過(guò)消息的類型判斷要讀取的信息。
2、消息隊(duì)列操作的系列函數(shù)
(1)消息隊(duì)列的創(chuàng)建 msgget()
#include
(2)消息隊(duì)列的收發(fā)信息msgsnd()msgrcv()
#include
(3)消息隊(duì)列的刪除 msgctl()
#include
3、消息隊(duì)列通信簡(jiǎn)單示例
pthread1.c :-----------》
#define SIZE 64
//數(shù)據(jù)接收結(jié)構(gòu)體
struct msg_rv
{
int mtype;
char msg[50];
};
//數(shù)據(jù)發(fā)送結(jié)構(gòu)體
struct msg_snd
{
int mtype;
char msg[50];
};
int main(void) {
int msgid;
struct msg_rv data;
struct msg_snd snddata;
char buff[50];
//獲取msgid
msgid = msgget((key_t)123,IPC_CREAT|0666);
if(msgid == -1) {
printf("msgid failed!\n");
return -1;
}
data.mtype = 88;
snddata.mtype = 89;
while(1) {
bzero(buff,50);
printf("please input data!\n");
fgets(buff,50,stdin);
strcpy(snddata.msg,buff);
if(strncmp(snddata.msg,"end",3)==0) {
break;
}
msgsnd(msgid,(void *)&snddata,strlen(buff)+4,0);//得到的值發(fā)送出去
usleep(20);
printf("run here!\n");
if(msgrcv(msgid,(void *)&data,sizeof(struct msg_rv),data.mtype,0)==-1) {
printf("msgsnd failed!\n");
return -1;
}
printf("receive data:%s\n",data.msg);
if(strncmp(data.msg,"end",3)==0) {
break;
}
}
//撤消消息隊(duì)列
msgctl(msgid,IPC_RMID,0);
return 0;
}
pthread2.c :------------------------》
#define SIZE 64
//數(shù)據(jù)接收結(jié)構(gòu)體
struct msg_rv
{
int mtype;
char msg[50];
};
//數(shù)據(jù)發(fā)送結(jié)構(gòu)體
struct msg_snd
{
int mtype;
char msg[50];
};
int main(void)
{
int msgid;
struct msg_rv data;
struct msg_snd snddata;
char buff[50];
data.mtype = 89;
snddata.mtype = 88;
//獲取msgid
msgid = msgget((key_t)123,IPC_CREAT|0666);
if(msgid == -1) {
printf("msgid failed!\n");
return -1;
}
while(1) {
//接受
if(msgrcv(msgid,(void *)&data,sizeof(struct msg_rv),data.mtype,0)==-1)
{
printf("msgsnd failed!\n");
return -1;
}
printf("receive data:%s\n",data.msg);
if(strncmp(data.msg,"end",3)==0) {
break;
}
//發(fā)送
printf("please input data:\n");
bzero(buff,50);
fgets(buff,50,stdin);
strcpy(snddata.msg,buff);
printf("data = %s\n",snddata.msg);
if(strncmp(snddata.msg,"end",3)==0) {
break;
}
msgsnd(msgid,(void *)&snddata,strlen(buff)+4,0);//得到的值發(fā)送出去
printf("run here!\n");
}
//撤消消息隊(duì)列
msgctl(msgid,IPC_RMID,0);
return 0;
}
信號(hào)量協(xié)調(diào)不同進(jìn)程對(duì)于共享資源的訪問(wèn),它是不同進(jìn)程間或一個(gè)給定進(jìn)程內(nèi)部不同線程間同步的機(jī)制。
1、信號(hào)量概述
(1)二值信號(hào)量
值為0或1。與互斥鎖類似,資源可用時(shí)值為1,不可用時(shí)值為0
(2)計(jì)數(shù)信號(hào)量
值在0到n之間。用來(lái)統(tǒng)計(jì)資源,其值代表可用資源數(shù)
(3)對(duì)信號(hào)量的操作
P操作:即申請(qǐng)資源,亦即將信號(hào)量值減1,可能引起進(jìn)程睡眠。
V操作:即釋放資源,亦即將信號(hào)量值加1,V操作從不會(huì)睡眠。
等0操作:不申請(qǐng)也不釋放資源,而是令進(jìn)程阻塞直到信號(hào)量的值為0為止
2、信號(hào)量相關(guān)的接口函數(shù)
(1) 創(chuàng)建信號(hào)量集合semget()
#include
(2)設(shè)置/刪除信號(hào)量集 semctl()
#include
(3)信號(hào)量的PV操作 semop()
核心:信號(hào)量為 <=0 時(shí)進(jìn)行p操作,會(huì)阻塞程序,直到另一進(jìn)程中是該信號(hào)進(jìn)行了v操作后,本程序才會(huì)繼續(xù)運(yùn)行------》key值相同,信號(hào)量共通
p 減一操作
v 加一操作
#include
3、信號(hào)量協(xié)同共享內(nèi)存示例代碼
pthread1.c :-----------》
int main()
{
int semid;
int shmid;
char *p;
struct sembuf mysembuf1,mysembuf2;
mysembuf1.sem_num = 0;
mysembuf1.sem_flg = SEM_UNDO;
mysembuf1.sem_op = 1;
mysembuf2.sem_num = 1;
mysembuf2.sem_flg = SEM_UNDO;
mysembuf2.sem_op = -1;
// 創(chuàng)建信號(hào)量集合
semid = semget((key_t)789,2,IPC_CREAT|0666);
if(semid == -1) {
perror("creat sem failed!\n");
return -1;
}
// 創(chuàng)建共享內(nèi)存
shmid = shmget((key_t)456,1024,IPC_CREAT|IPC_EXCL|0666);
if((shmid == -1)&&(errno == EEXIST)) {
shmid = shmget((key_t)456,1024,0666);
}
// 映射共享內(nèi)存到進(jìn)程
p = (char *)shmat(shmid,NULL,0);
while(1) {
semop(semid,&mysembuf2,1); // 對(duì)信號(hào)量2進(jìn)行p操作(減一)
printf("the message I recv is:%s\n",p);
printf("please input a message!\n");
scanf("%s",p);
printf("message is %s\n",p);
semop(semid,&mysembuf1,1); // 對(duì)信號(hào)量1進(jìn)行v操作(加一)
}
//解除映射
shmdt(p);
//刪除共享內(nèi)存
shmctl(semid, IPC_RMID, NULL);
}
pthread2.c :-----------》
int main() {
int semid;
int shmid;
char *p;
struct sembuf mysembuf1,mysembuf2;
mysembuf1.sem_num = 0; // 信號(hào)集合中的第一個(gè)信號(hào)
mysembuf1.sem_flg = SEM_UNDO;
mysembuf1.sem_op = -1; //p操作
mysembuf2.sem_num = 1; // 信號(hào)集合中的第二個(gè)信號(hào)
mysembuf2.sem_flg = SEM_UNDO;
mysembuf2.sem_op = 1; // v操作
// 創(chuàng)建信號(hào)量集合
semid = semget((key_t)789,2,IPC_CREAT|0666);
if(semid == -1) {
perror("creat sem failed!\n");
return -1;
}
// 設(shè)置信號(hào)量的值
semctl(semid,0,SETVAL,1); //第一個(gè)信號(hào)量初值為1
printf("sem num is:%d\n",semctl(semid,0,GETVAL));
semctl(semid,1,SETVAL,0); //第二個(gè)信號(hào)量初值為0
printf("sem num is:%d\n",semctl(semid,1,GETVAL));
// 創(chuàng)建共享內(nèi)存
shmid = shmget((key_t)456,1024,IPC_CREAT|IPC_EXCL|0666);
if((shmid == -1)&&(errno == EEXIST)) {
shmid = shmget((key_t)456,1024,0666);
}
// 映射共享內(nèi)存到進(jìn)程
p = (char *)shmat(shmid,NULL,0);
while(1) {
semop(semid,&mysembuf1,1); // 對(duì)信號(hào)量1進(jìn)行p操作(減一)不阻塞,因?yàn)槌踔禐?
// 執(zhí)行完這句話以后信號(hào)量的值就立馬變成1
printf("the message I recv is:%s\n",p);
printf("please input a message!\n");
scanf("%s",p);
printf("message is %s\n",p);
semop(semid,&mysembuf2,1); // 對(duì)信號(hào)量2進(jìn)行v操作(加一)不阻塞,因?yàn)槌踔禐?
}
//解除映射
shmdt(p);
//刪除共享內(nèi)存
shmctl(semid, IPC_RMID, NULL);
}
2.3 IPC shell命令操作
ipcs -q 查看消息隊(duì)列
ipcrm -q MSG_ID 刪除消息隊(duì)列
ipcs -m 查看共享內(nèi)存
ipcrm -m SHM_ID 刪除共享內(nèi)存
ipcs -s 查看信號(hào)量
ipcrm -s SEM_ID 刪除信號(hào)量
2.2 進(jìn)程間通訊方式比較
pipe: 具有親緣關(guān)系的進(jìn)程間,單工,數(shù)據(jù)在內(nèi)存中
fifo: 可用于任意進(jìn)程間,雙工,有文件名,數(shù)據(jù)在內(nèi)存
signal: 唯一的異步通信方式
msg:常用于cs模式中, 按消息類型訪問(wèn) ,可有優(yōu)先級(jí)
shm:效率最高(直接訪問(wèn)內(nèi)存) ,需要同步、互斥機(jī)制
sem:配合共享內(nèi)存使用,用以實(shí)現(xiàn)同步和互斥
以上就是關(guān)于“l(fā)inux可不可以創(chuàng)建多個(gè)進(jìn)程”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。