Chinaunix首页 | 论坛 | 博客
  • 博客访问: 181526
  • 博文数量: 54
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2018
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-31 23:14
文章存档

2014年(2)

2013年(52)

分类: 嵌入式

2013-08-26 20:51:38

如何进程间通信?
1,fork后复制出的子进程都默认打开三个流,但都是虚拟的,文件描述符相同不一定是相同的文件(文件描述符分别不同,0,1,2相同。3开始的可能相同;),不可取
2,两个程序,产生两个进程。对于这两个进程可以操作同一个文件达到共享。


*********************************************************************************
进程间通信可以:
    1,无名管道;
    2,有名管道;
    3,信号量;
    4,信号
    5,IPC对象,共享内核区
    6,IPC对象,消息队列
    7,信号灯


************************************************************************
1,无名管道:
pipe默认打开两个管道文件,一个0读1写;
fork产生子进程后,直接对无名管道进行操作。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>

  4. int main()
  5. {
  6.     int fd[2];

  7.     if(-1 == pipe(fd))
  8.     {
  9.         perror("pipe");
  10.         exit(-1);
  11.     }

  12.     printf("%d %d\n", fd[0], fd[1]);//结果:3,4

  13.     pid_t pid = fork();
  14.     if(0 == pid)
  15.     {
  16.         close(fd[1]);//两个进程,一个进程只操作一个fd
  17.         sleep(3); //子进程读,父进程写
  18.         char buf[100] = {0};
  19.         read(fd[0], buf, 100);
  20.         printf("%s\n", buf);
  21.     }
  22.     else
  23.     if(0 < pid)
  24.     {
  25.         close(fd[0]);
  26.         write(fd[1], "hello", 5);
  27.     }
  28.     else
  29.     {
  30.         perror("fork");
  31.         exit(-1);
  32.     }

  33. }
***************************************************************
2,有名管道:server.c产生写端:(两个程序前创建一个fifo管道文件)

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <stdlib.h>

  6. int main(int argc, char **argv)
  7. {
  8.     if(2 != argc)
  9.     {
  10.         printf("Usage: %s \n", argv[0]);
  11.         exit(-1);
  12.     }

  13.     int fd;
  14.     if(-1 == (fd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0666)))//管道文件操作同普通文件操作
  15.     {
  16.         perror("open");
  17.         exit(-1);
  18.     }
  19.     
  20.     char buf[100];
  21.     while(1)
  22.     {
  23.         printf("input: ");fflush(stdout);
  24.         gets(buf);
  25.         write(fd, buf, 100);
  26.     }

  27. }
            client.c产生读端:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <stdlib.h>
  6. #include <strings.h>

  7. int main(int argc, char **argv)
  8. {
  9.     if(2 != argc)
  10.     {
  11.         printf("Usage: %s \n", argv[1]);
  12.         exit(-1);
  13.     }

  14.     int fd;
  15.     if(-1 == (fd = open(argv[1], O_RDONLY)))
  16.     {
  17.         perror("open");
  18.         exit(-1);
  19.     }
  20.     char buf[100] = {0};    
  21.     while(1)
  22.     {
  23.         bzero(buf, 100);
  24.         read(fd, buf, 100);

  25.         if(0 == strncmp(buf, "time", 4))//如果是time quit则服务器端做出相应操作。
  26.         {
  27.             time_t t = time(NULL);
  28.             printf("recv :%s\n", ctime(&t));
  29.             
  30.         }
  31.         else
  32.         if(0 == strncmp(buf, "quit", 4))
  33.         {
  34.             exit(0);
  35.         }
  36.         else
  37.             printf("recv :%s\n", buf);//其他直接打印
  38.     }
  39. }
****************************************************************
3,信号量:类似线程信号量通信
hello.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <fcntl.h> /* For O_* constants */
  3. #include <sys/stat.h> /* For mode constants */
  4. #include <semaphore.h>
  5. #include <stdlib.h>

  6. int main()
  7. {
  8.     sem_t *a = sem_open("/mysem", O_CREAT, 0666, 1);
  9.     if(SEM_FAILED == a)
  10.     {
  11.         perror("sem_open");
  12.         exit(-1);
  13.     }

  14.     sem_t *b = sem_open("/mysem1", O_CREAT, 0666, 0);
  15.     if(SEM_FAILED == b)
  16.     {
  17.         perror("sem_open");
  18.         exit(-1);
  19.     }

  20.     while(1)
  21.     {
  22.         sem_wait(a);
  23.         sleep(1);
  24.         printf("hello\n");
  25.         sem_post(b);
  26.     }
  27. }
world.c
点击(此处)折叠或打开
  1. #include <stdio.h>
  2. #include <fcntl.h> /* For O_* constants */
  3. #include <sys/stat.h> /* For mode constants */
  4. #include <semaphore.h>
  5. #include <stdlib.h>

  6. int main()
  7. {
  8.     sem_t *a = sem_open("/mysem", O_CREAT, 0666, 1);
  9.     if(SEM_FAILED == a)
  10.     {
  11.         perror("sem_open");
  12.         exit(-1);
  13.     }

  14.     sem_t *b = sem_open("/mysem1", O_CREAT, 0666, 0);
  15.     if(SEM_FAILED == b)
  16.     {
  17.         perror("sem_open");
  18.         exit(-1);
  19.     }

  20.     while(1)
  21.     {
  22.         sem_wait(b);
  23.         sleep(1);
  24.         printf("world\n");
  25.         sem_post(a);
  26.     }
  27. }
****************************************************************
4,信号通信:信号是软件层次上对中断机制的一种模拟,异步通信。
               信号可以直接进行用户空间和内核空间之间进行交互,内核也可以通过它通知用户空间进程发生了哪些事。
               如果该进程当前并未处于执行状态,则该信号就由内核保存起来,直到该进程恢复执行再传递给他;
                                                              ----如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到取消阻塞才被传递给进程。

            kill函数发送信号(-l,查看系统支持的信号列表);raise函数允许向自己发送信号。


    如:signal(SIGUSR1, fun);signal函数是自定义收到信号的动作函数;这里定义本进程接收到SIGUSR1信号的动作(执行fun函数)。
          kill(pid, SIGUSR2);kill函数用于发送信号;给pid号进程发信号SIGUSR2。
          signal和kill函数配合使用。

    信号可以打断任意的阻塞,被打断后的反应:
                                                            1,结束阻塞;
                                                            2,重启阻塞了的系统调用
                            如:int main(){
                                  signal(sigusr1,fun);
                                  sleep(10);//阻塞状态
                                  printf();
                                  }
                                  未到10秒收到信号,则提前打印;即结束阻塞。
                                  如:int main(){
                                    signal(sigusr1,fun);
                                    gets();//阻塞状态或者为其他阻塞函数如kill其他进程。
                                    printf();
                                    }
                                    收到信号,则重启gets调用或再次调用kill。

    alarm();可以在进程中设置一个定时器,指定时间到,内核就向进程发送SIGALARM信号
                             如:
                                void fun(int a)
                                {
                                    printf("hello\n");
                                    alarm(3);
                                    }
                                    int main()
                                    {
                                    signal(SIGALRM, fun);
                                    alarm(3);
                                    printf("alarm ....!\n");
                                    while(1);
                                    }可以完成循环打印hello。

    pause();调用后挂起进程直到收到信号;可以节省CPU资源。


当外部发送11的信号给该进程后,该进程才会执行打印right。

点击(此处)折叠或打开

  1. #include <signal.h>
  2. #include <stdio.h>

  3. void fun(int a)
  4. {
  5.     printf("right!\n");
  6.     exit(0);
  7. }


  8. int main()
  9. {
  10.     signal(11, SIG_IGN);

  11.     printf("changed!\n");

  12.     while(1);//适当的方法是while(1)pause();使程序暂停。
  13. }
******************************************************************
IPC对象-共享内存:
            ipcs;查看所有共享内存的对象
            ipcs -m;查看共享内存的对象-内存共享
            ipcs -q;查看共享内存的对象-消息队列
5,对象-内存共享:
server.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/ipc.h>
  3. #include <sys/shm.h>
  4. #include <string.h>
  5. #include <stdlib.h>

  6. int main()
  7. {
  8.     key_t key = ftok("/", 'a');/ftok和shmget组合使用
  9.     int shm_id = shmget(key, 100, IPC_CREAT|0666);//key为任意值,申请内存
  10.     if(-1 == shm_id)
  11.     {
  12.         perror("shmget");
  13.         exit(-1);
  14.     }
  15.     char *p = shmat(shm_id, NULL, 0666);//创建映射关系p和这段内存的关系
  16.     strcpy(p, "hello");
  17. }
client.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/ipc.h>
  3. #include <sys/shm.h>
  4. #include <string.h>
  5. #include <stdlib.h>

  6. int main()
  7. {
  8.     key_t key = ftok("/", 'a');
  9.     int shm_id = shmget(key, 100, 0666);//申请一块共同的内存
  10.     if(-1 == shm_id)
  11.     {
  12.         perror("shmget");
  13.         exit(-1);
  14.     }
  15.     char *p = shmat(shm_id, NULL, 0666);//映射关系,类型自定义
  16.     printf("%s\n", p);
  17.     shmdt(p);//删除映射关系
  18.     shmctl(shm_id, IPC_RMID, NULL);//释放内核内存区

  19. }
**************************************************
6,IPC对象,消息队列
        就是一个消息的列表,用户在列表中添加消息,读取消息。遵循队列的规则:先进先出,出后消息消失。
        可以指定读取消息队列中为“ID”的消息(多次读该“ID”,则限定该ID消息读完为止)。(发消息时可以定各个消息的ID号)
server.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/msg.h>
  5. #define SIZE 100
  6. typedef struct buf{
  7.     long type;
  8.     char msg[SIZE];
  9. }BUF;

  10. int main()
  11. {
  12.     int msg_id = msgget(888, IPC_CREAT | 0666);//初始化消息队列
  13.     if(-1 == msg_id)//888:和队列相关的key值,用户指定,任意值|| IPC_CREAT | 0666:消息队列访问权限
  14.     {
  15.         perror("msgget");
  16.         exit(-1);
  17.     }

  18.     BUF buf = {1, "hello1"};
  19.     msgsnd(msg_id, &buf, SIZE, 0);//发送消息,msg_id队列号。||&buf特殊结构体type(即整形自定义“ID”)和自己的消息msg;。。;0表示发送完成才返回函数。
  20.     BUF buf1 = {1, "hello1"};
  21.     msgsnd(msg_id, &buf1, SIZE, 0);
  22.     BUF buf2 = {2, "hello2"};
  23.     msgsnd(msg_id, &buf2, SIZE, 0);
  24.     BUF buf3 = {1, "hello1"};
  25.     msgsnd(msg_id, &buf3, SIZE, 0);
  26.     BUF buf4 = {7, "hello7"};
  27.     msgsnd(msg_id, &buf4, SIZE, 0);
  28. }
client.c  //调用:./a.out ID
点击(此处)折叠或打开
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/msg.h>

  5. #define SIZE 100
  6. typedef struct buf{
  7.     long type;
  8.     char msg[SIZE];
  9. }BUF;
  10. int main(int argc, char **argv)
  11. {
  12.     if(2 != argc)
  13.     {
  14.         printf("Usage: %s \n", argv[0]);
  15.         exit(-1);
  16.     }
  17.     int msg_id = msgget(888, 0666);
  18.     if(-1 == msg_id)
  19.     {
  20.         perror("msgget");
  21.         exit(-1);
  22.     }
  23.     BUF buf;
  24.     msgrcv(msg_id, &buf, SIZE, atoi(argv[1]), 0);//接收消息函数:msg_id队列号;atoi(argv[1])前面提到的“ID”,0:无消息阻塞
  25.     printf("%s\n", buf.msg);
  26.     msgctl(msg_id, IPC_RMID, NULL);//IPC_RMID删除消息队列。
  27. }
***********************************************************
7,信号灯:信号量集
也叫信号量,是对信号量的封装。
是不同进程和给定进程内部线程同步的机制。
一次性创建多个信号灯。
hello.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/sem.h>
  5. #include <stdlib.h>
  6. void P(int sem_id, int num)
  7. {
  8.     struct sembuf buf = {num, -1, 0};//特定结构体,信号灯编号,分配资源p操作、执行,0防死锁(死循环);
  9.     semop(sem_id, &buf, 1);1为要操作信号灯次数。
  10. }
  11. void V(int sem_id, int num)
  12. {
  13.     struct sembuf buf = {num, 1, 0};//释放资源v操作,加1,防死锁
  14.     semop(sem_id, &buf, 1);
  15. }
  16. int main()
  17. {
  18.     int sem_id = semget(888, 3,IPC_CREAT | 0666);//创建三个信号灯和信号灯关联的key 888; 访问权限。
  19.     if(-1 == sem_id)
  20.     {
  21.         perror("semget");
  22.         exit(-1);
  23.     }    
  24.     semctl(sem_id, 0, SETVAL, 1);信号灯集编号,信号灯编号,SETVAL为设置信号灯值,值为1(同信号sem加1;减1)。
  25.     semctl(sem_id, 1, SETVAL, 0);
  26.     semctl(sem_id, 2, SETVAL, 0);

  27.     while(1)
  28.     {
  29.         P(sem_id, 0);
  30.         printf("hello\n");
  31.         V(sem_id, 1);
  32.     }
  33. }
the.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/sem.h>
  5. #include <stdlib.h>
  6. void P(int sem_id, int num)
  7. {
  8.     struct sembuf buf = {num, -1, 0};
  9.     semop(sem_id, &buf, 1);
  10. }
  11. void V(int sem_id, int num)
  12. {
  13.     struct sembuf buf = {num, 1, 0};
  14.     semop(sem_id, &buf, 1);
  15. }
  16. int main()
  17. {
  18.     int sem_id = semget(888, 3, 0666);//每个进程都要执行的语句,这里不用creat
  19.     if(-1 == sem_id)
  20.     {
  21.         perror("semget");
  22.         exit(-1);
  23.     }    
  24.     while(1)
  25.     {
  26.         P(sem_id, 1);
  27.         printf("the\n");
  28.         V(sem_id, 2);
  29.     }
  30. }
world.c

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/ipc.h>
  4. #include <sys/sem.h>
  5. #include <stdlib.h>
  6. void P(int sem_id, int num)
  7. {
  8.     struct sembuf buf = {num, -1, 0};
  9.     semop(sem_id, &buf, 1);
  10. }
  11. void V(int sem_id, int num)
  12. {
  13.     struct sembuf buf = {num, 1, 0};
  14.     semop(sem_id, &buf, 1);
  15. }
  16. int main()
  17. {
  18.     int sem_id = semget(888, 3, 0666);
  19.     if(-1 == sem_id)
  20.     {
  21.         perror("semget");
  22.         exit(-1);
  23.     }    
  24.     while(1)
  25.     {
  26.         P(sem_id, 2);
  27.         printf("world\n");
  28.         V(sem_id, 0);
  29.     }
  30. }
******************************************
进程线程小结:
线程:

        可重入性,线程安全函数
        同步互斥,过程需要同步, 临界资源需要互斥

线程间通信
        全局变量
        信号量(无名信号量(内存):sem_t t;)
        互斥锁

进程:

        内存映射,

原始进程间通信方法
        信号量(有名信号量sem_t *t = sem_open())

        无名管道
        有名管道

        信号

        IPC对象,共享内核区
        IPC对象,消息队列
        信号灯

阅读(4021) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~