系統(tǒng)運(yùn)維
上次說到的,不能做到實(shí)時(shí)通信。那么開兩個(gè)進(jìn)程就可以了,一個(gè)用來監(jiān)聽是否有消息傳來,一個(gè)用來等待用戶輸入。那么,先來復(fù)習(xí)一下進(jìn)程的相關(guān)概念。
linux中進(jìn)程包含PCB(進(jìn)程控制塊)、程序以及程序所操縱的數(shù)據(jù)結(jié)構(gòu)集,可分為“代碼段”、“數(shù)據(jù)段”和“堆棧段”。
進(jìn)程狀態(tài)運(yùn)行狀態(tài)R(TASK_RUNNING)
可中斷睡眠狀態(tài)S(TASK_INTERRUPTIBLE)
不可中斷睡眠狀態(tài)D(TASK_UNINTERRUPTIBLE)
暫停狀態(tài)T(TASK_STOPPED或TASK_TRACED)
僵死狀態(tài)Z(TASK_ZOMBIE)
退出狀態(tài)X(TASK_DEAD)
ps -aux 查看進(jìn)程信息,可以看到各進(jìn)程的狀態(tài):
所有進(jìn)程的父進(jìn)程
init進(jìn)程絕不會終止。
它是一個(gè)普通的用戶進(jìn)程(與交換進(jìn)程不同,它不是內(nèi)核中的系統(tǒng)進(jìn)程),但是它以超級用戶特權(quán)運(yùn)行。
獲取進(jìn)程標(biāo)識#include < sys/types.h>
#include < unistd.h>
pid_t getpid(void); 返回:調(diào)用進(jìn)程的進(jìn)程I D
pid_t getppid(void); 返回:調(diào)用進(jìn)程的父進(jìn)程I D
uid_t getuid(void); 返回:調(diào)用進(jìn)程的實(shí)際用戶I D
uid_t geteuid(void); 返回:調(diào)用進(jìn)程的有效用戶I D
gid_t getgid(void); 返回:調(diào)用進(jìn)程的實(shí)際組I D
gid_t getegid(void); 返回:調(diào)用進(jìn)程的有效組I D
#include < sys/types.h>
#include < unistd.h>
pid_t fork(void);
返回:子進(jìn)程中為0,父進(jìn)程中為子進(jìn)程I D,出錯為-1
注意:
1、使用fork函數(shù)得到的子進(jìn)程從父進(jìn)程的繼承了整個(gè)進(jìn)程的地址空間,包括:
進(jìn)程上下文、進(jìn)程堆棧、內(nèi)存信息、打開的文件描述符、信號控制設(shè)置、進(jìn)程優(yōu)先級、進(jìn)程組號、當(dāng)前工作目錄、根目錄、資源限制、控制終端等。
2、子進(jìn)程與父進(jìn)程的區(qū)別在于:
1)父進(jìn)程設(shè)置的鎖,子進(jìn)程不繼承
2)各自的進(jìn)程ID和父進(jìn)程ID不同
3)子進(jìn)程的未決告警被清除;
4)子進(jìn)程的未決信號集設(shè)置為空集。
3、fork系統(tǒng)調(diào)用之后,父子進(jìn)程將交替執(zhí)行。
4、如果父進(jìn)程先退出,子進(jìn)程還沒退出。那么子進(jìn)程的父進(jìn)程將變?yōu)閕nit進(jìn)程。(注:任何一個(gè)進(jìn)程都必須有父進(jìn)程)
5、如果子進(jìn)程先退出,父進(jìn)程還沒退出,那么子進(jìn)程必須等到父進(jìn)程捕獲到了子進(jìn)程的退出狀態(tài)才真正結(jié)束,否則這個(gè)時(shí)候子進(jìn)程就成為僵進(jìn)程。(這是不好的,這樣子進(jìn)程會一直占用內(nèi)存資源)
解決辦法:
1)wait函數(shù):使父進(jìn)程阻塞,直到一個(gè)子進(jìn)程結(jié)束或者該進(jìn)程收到一個(gè)指定信號為止。(但是,這樣不好)
2)signal(SIGCHLD,SIG_IGN)。表示父進(jìn)程忽略SIGCHLD,該信號是子進(jìn)程退出的時(shí)候向父進(jìn)程發(fā)出的,由init進(jìn)程收。
接下來,可以繼續(xù)我們上次的小程序了。
#include < stdio.h>
#include < sys/types.h>
#include < signal.h>
#include port.h
#include readConfig.h
// 1、主機(jī)與虛擬機(jī)
int main()
{
int fd,pid,child_id;
char filename[20] = serial.cfg;
char recbuf[100] = ;
char sendbuf[100] = ;
struct t_port port = {0};
//從文件獲取配置信息
getMsg(filename,&port);
//串口初始化
fd = portInit(port.devname,port.speed,port.data,port.parity,port.stop);
//主機(jī)與虛擬機(jī)串口通信
pid = fork();
if(pid == -1)
{
perror(create process);
return 1;
}
else if(pid == 0) //子進(jìn)程 接收消息
{
child_id = getpid();
while(read(fd,recbuf,100)>0) //這里不能用strlen。因?yàn)殚_始strlen(recbuf)=0
{
if(strcmp(recbuf,) != 0)
{
printf(receive msg: %s\\n,recbuf);
putchar(\'$\');
fflush(stdout);
}
memset(recbuf,0,100);
}
}
else //(主)父進(jìn)程 發(fā)送消息
{
printf($);
while(1)
{
memset(sendbuf,0,100);
scanf(%s,sendbuf);
if(strcmp(sendbuf,over) == 0) //但是,此時(shí),子進(jìn)程未結(jié)束,還在后臺運(yùn)行
{
break;
}
if(write(fd,sendbuf,strlen(sendbuf)) > 0)
{
printf($);
}
}
}
close(fd);
return 0;
}
//2、虛擬機(jī)兩串口
/*
int main(int argc,char *argv[])
{
int fd,pid;
char receivebuf[100] = ;
char sendbuf[100] = ;
if(argc != 2)
{
printf(format error!\\n);
return 1;
}
if( strcmp(argv[1],ttyS0)==0)
{
fd = portInit(/dev/ttyS0,115200,8,0,1);
}
else if(strcmp(argv[1],ttyS1)==0)
{
fd = portInit(/dev/ttyS1,115200,8,0,1);
}
else
{
printf(format error!\\n);
return 1;
}
pid = fork();
if(pid == -1)
{
perror(create process);
return 1;
}
else if(pid == 0) //子進(jìn)程
{
//接收消息
while(read(fd,receivebuf,sizeof(receivebuf)) > 0)
{
if(strcmp(receivebuf,) != 0)
{
printf(receive msg : %s\\n,receivebuf);
}
memset(receivebuf,0,100);
}
}
else //父進(jìn)程
{
//發(fā)送消息
while(1)
{
memset(sendbuf,0,100);
scanf(%s,sendbuf);
if(strcmp(sendbuf,-over) == 0)
{
break;
}
write(fd,sendbuf,strlen(sendbuf));
printf(send OK\\n);
}
}
close(fd);
return 0;
}
*/
運(yùn)行結(jié)果:
發(fā)現(xiàn)問題了沒?對的。父進(jìn)程會先死。
程序運(yùn)行時(shí):
程序結(jié)束時(shí):
如何解決呢?下次說~