linux 多進程編程有如下要點
第一:首當其沖的是進程狀態,我把本地的ubuntu進程截圖了一份,請看:

進程的狀態如下:
R:running,運行狀態。
S:可中斷的睡眠狀態。
D:不可中斷的睡眠狀態。
T:暫停狀態。
Z:僵屍狀態。
<:高優先級別
N:低優先級別
+:前台進程
第二,創建進程
函數定義:pid_t fork();
成功時,返回進程id,失敗時返回-1. 參考例子如下:
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid=fork();
if(pid==0)
{
fputs("Hi i am child proc...",stdout);
}
else{
fputs("Child proc id is: %d \n ",stdout);
sleep(30);
}
if(pid==0)
{
puts("End child process");
}
else{
puts("End parent process");
}
return 0;
}
當pid==0時,是子進程代碼運行區域。其他則是父進程運行區域。由於父進程沒有接收到子進程的返回值,這樣子進程會轉換為僵屍進程。
第三 僵屍進程的處理
1)wait 方法:wait方法會一直阻塞當前進程運行,直到有當前進程的子進程結束,wait方法會返回。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
int status;
pid_t id=fork();
if(id==0)
{
return 4;
}
else{
printf("child proc id is: %d \n",id);
wait(&status);
if(WIFEXITED(status))
{
printf("THe child process return normal:%d \n ",WEXITSTATUS(status));
}
sleep(30);
}
if(id==0)
{
fputs("The child process ends..\n",stdout);
}
else{
fputs("The parent process ends..\n",stdout);
}
return 0;
}
2)waitpid 方法:該方法不會阻塞當前進程。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid = fork();
int status;
if(pid==0)
{
puts("The child process running....");
sleep(9);
exit(24);
}
else{
while(!waitpid(pid,&status,WNOHANG))
{
sleep(3);
puts("3 seconds...");
}
if(WIFEXITED(status))
{
printf("Child sent is: %d \n",WEXITSTATUS(status));
}
}
return 0;
}
3)使用信號處理機制,核心在於signal 方法
signal 方法第一個參數為事件名稱。第二個參數為第一個參數事件發生時,需要調用的函數。
事件主要有三個:
SIGCHLD,當前進程的子進程結束時會自動發出這個信號。
SIGINT,當用戶按ctrl c時,系統會發出這個信號。
SIGALRM.系統的alarm函數運行到期后,會發出這個信號。
例子如下:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void timeout(int sig)
{
printf("time out is: %d \n",sig);
if(sig==SIGALRM)
{
puts("time out....");
}
alarm(2);
}
void keycontrol(int sig)
{
printf("keycontrol is: %d \n",sig);
if(sig==SIGINT)
{
puts("Ctrl c pressed..");
}
}
int main()
{
signal(SIGINT,keycontrol);
signal(SIGALRM,timeout);
alarm(3);
puts("hahahahahah");
int i;
for(i=0;i<3;i++)
{
puts("wait.....");
sleep(30);
}
return 0;
}
4)sigaction函數,這個函數是跨平台的。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void timeout(int sig)
{
if(sig==SIGALRM)
{
puts("time out....");
}
alarm(2);
}
int main()
{
int i=0;
struct sigaction sig;
sig.sa_handler=timeout;
sig.sa_flags=0;
sigemptyset(&sig.sa_mask);
sigaction(SIGALRM,&sig,0);
alarm(2);
for(i=0;i<100;i++)
{
sleep(100);
puts("wait....");
}
return 0;
}
這里結構體sigaction的sa_flags=0,sa_mask 都用0即可。sa_handler用來指定處理函數。
第四:進程通信
由於進程是獨立的內存結構,因此進程間不存在共享變量,所以使用管道,管道是內核所有的。見如下例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
void readProc(int sig)
{
if(sig==SIGCHLD)
{
int status;
waitpid(-1,&status,WNOHANG);
if(WIFEXITED(status))
{
printf("received from child is: %d \n",WEXITSTATUS(status));
sleep(30);
}
}
}
int main()
{
struct sigaction sig;
sig.sa_handler=readProc;
sigemptyset(&sig.sa_mask);
sig.sa_flags=0;
sigaction(SIGCHLD,&sig,0);
int fd1[2],fd2[2];
char str1[] = "who are you";
char str2[] = "I am lucy";
char buf[50];
pipe(fd1);
pipe(fd2);
pid_t id;
id = fork();
if(id==0)
{
write(fd1[1],str1,sizeof(str1));
read(fd2[0],buf,50);
printf("child proc recived from parent is: %s \n",buf);
return 88;
}else{
read(fd1[0],buf,50);
write(fd2[1],str2,sizeof(str2));
printf("parent proc recived from child is: %s \n",buf);
sleep(40);
}
return 0;
}
