Linux下进程间通信(嵌入式面试题)

                                                                          2016-10-28,14:53,Fri

   题目:c编程---在终端输入(Num,Cmd),Num代表队员号,Cmd代表命令。Cmd为1,奔跑; Cmd为2,显示已奔跑时间(精确到ms); Cmd为3,停止奔跑并显示所有队员的状态(状态0:未奔跑; 状态1:正在奔跑; 状态2:奔跑过但已停止)。

  单进程:每个队员匹配一个信息结构体:Struct{int num;int cmd;int time;int status};使用switch(msg[num].cmd) 执行对应操作来改变 msg[num].timemsg[num.]status即可。   

  多进程:每个队员匹配一个进程。子进程睡眠态-->状态1,运行态-->状态2,暂停态-->状态3. 而进程间通信我们选用消息队列和信号的方法:

子进程被创建之后,因msgrcv()而处于阻塞态(即睡眠态)。接收到特定msg,便进入运行态while(1)。接收SIGUSR1信号时,将运行时间发送给父进程。接收到SIGSTOP信号时进入暂停态,且父进程中获取各子程序的状态。


simple flowchartresult

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 1 #include "head.h"
 2 
 3 struct {
 4     long mtype;
 5     int  mcmd;
 6     clock_t  mtv;
 7 }msg;
 8 pid_t  pid[6];
 9 int fd[6];
10 key_t key;
11 char dir[64];
12 char * p;
13 int msqid, i, num, cmd, status;
14 
15 void send_running_time(int arg);  //获得运行时间并发送
16 void recv_running_time();
17 void recycle_child(int arg);   //杀死各子进程并回收资源
18 void get_fds();
19 void get_status();    //获取子进程状态
20 
21 int main(int argc, const char *argv[])
22 {
23     key = ftok(".", 345);
24     if(key < 0){
25         perror("ftok failed");
26         return -errno;
27     }
28 
29     msqid = msgget(key, IPC_CREAT|IPC_EXCL|0664);
30     if(msqid <= 0){
31         if(errno == EEXIST){
32             msqid = msgget(key, 0664);
33         }else{
34             perror("msgget failed\n");
35             return -errno;
36         }
37     }
38 
39     for(i = 1; i < 6; i++){
40         pid[i] = fork();
41         if(pid[i] < 0){
42             perror("fork failed\n");
43             return -errno;
44         }else if(pid[i] == 0){
45             msgrcv(msqid, &msg, sizeof(msg), i, 0);
46             signal(SIGUSR1, send_running_time);
47             while(1);
48         }else
49             ;
50     }
51 
52     signal(SIGINT, recycle_child);
53     while(1){
54         get_fds();
55         printf("*******Num && cmd*********\n");
56         scanf("%d,%d",&num, &cmd);
57         msg.mtype = num;
58         msg.mcmd  = cmd;
59         switch(cmd){
60         case 1:
61             msgsnd(msqid, &msg, sizeof(msg), 0);
62             printf("No.%d is start off running!\n", num);
63             break;
64         case 2:
65             kill(pid[num], SIGUSR1);
66             recv_running_time();
67             break;
68         case 3:
69             kill(pid[num], SIGTSTP);
70             sleep(1);
71             get_status();
72             break;
73         default:
74             perror("invalid cmd");
75             break;
76         }
77     }
78     return 0;
79 }
主函数
 1 void send_running_time(int arg)
 2 {
 3     msg.mtv = clock();
 4     msgsnd(msqid, &msg, sizeof(msg), 0);
 5 }
 6 
 7 void recv_running_time()
 8 {
 9     msgrcv(msqid, &msg, sizeof(msg), num, 0);
10     printf("No.%ld  has run %ld ms\n",msg.mtype, msg.mtv/1000);
11 }
12 
13 void recycle_child(int arg)
14 {
15     for(i = 1; i < 6; i++){
16         kill(SIGKILL, pid[i]);
17         waitpid(pid[i], &status, WNOHANG );
18     }
19     exit(0);
20 }
21 
22 void get_fds()
23 {
24     for(i = 1; i < 6; i++){
25         sprintf(dir,"/proc/%d/status",pid[i]);
26         fd[i] = open(dir,O_RDONLY); 
27     }
28 }
29 
30 void get_status()
31 {
32     for(i = 1; i < 6; i++){
33         read(fd[i], dir, sizeof(dir));
34         p = strtok(dir, "\n");
35         p = strtok(NULL, "\n");
36         printf("No.%d\t%s\n",i, p);
37     }
38 }
子函数

 

TIPS:   

  • 子进程会对父进程的.data和.bss段精准复制,父进程在fork各子进程时,全局变量 i 的值均不同,所以 i 可以作为子进程中msgrcv()的long mtype值。
  • 使用for循环fork()子程序时留心递归创建。   
  • 子进程在while(1)时可接收signal并作相应处理。   
  • 重载Ctrl+c,使其结束父进程时杀死各子进程并回收资源(recycle_child())。  
  • open("/proc/pid/status/",O_RDONLY)可查看对应进程的状态(get_status())。
  • clock()函数获得进程running态时间,而不计sleeping等其他态时间。
posted on 2016-10-28 14:52  luopu  阅读(1635)  评论(0编辑  收藏  举报