[linux]进程(七)——进程通信

进程间通信
一,管道,
管道的限制:
(1)半双工,数据只能在一个方向上流动
(2)管道一般只在具有公共祖先的进程之间使用,通常一个管道由一个进程创建,然后该进程调用fork()函数,此后父子进程可以使用该管道
管道的创建:

[cpp] view plaincopy

  1. #include <unistd.h>
  2. int pipe(int fileds[2]);  //filedes[0]为读而打开,filedes[1]为写而打开

向一个没有读进程关联的管道写数据,会产生SIGPIPE,内核对于SIGPIPE的默认动作是退出该进程,这个通常不是我们期望看到的,因此我们需要重载这个信号处理方法,signal(SIGPIPE,SIG_IGN);

二,FIFO
FIFO被称为命名管道,和PIPE不同的是,通过FIFO不相关的进程也能交换数据
创建FIFO的方式如下

[cpp] view plaincopy

  1. int mkfifo(const char*pathname,mode_t mode);

在创建了fifo后,一般对文件的操作函数都可以用于它,open close read write等,
fifo被多个进程用于写很常见,所以应该考虑进程间的同步,并且多个写进程写的数据之间不会穿插。答:PIPE_BUF规定了内核中管道缓冲区的大小,所有写的进程写的大小必须要小于PIPE_BUF的大小
FIFO可以用于客户进程与服务进程之间的通信,如何保证同步?
答:服务进程创建一个众所周知的FIFO用来接收客户进程的请求,然后根据客户进程id不一样,再为每个客户进程创建一个fifo用来给客户进程发送服务进程的回应消息,这样的问题是服务进程如何知道客户进程已经退出了?
FIFO的缺点是不支持随机访问,因为PIPE和FIFO都是先入先出的特点

三,消息队列
查看linux系统共享内存和消息队列的情况:

ipcs [-m|-q|-s]
-m 输出有关共享内存(shared memory)的信息
-q 输出有关信息队列(message queue)的信息
ipcrm命令

用来手动解除linux使用的共享内存~

四,共享内存
以下共享内存大部分来自以下网址点击打开链接
共享内存适合比较大的数据集,因为它使用内存,支持快速的随机访问,也是最快的IPC形式共享内存并不是从某一进程拥有的内存中划分出来的;进程的内存总是私有的
shm_open():创建共享内存段或连接到现有的已命名内存段。这个系统调用返回一个文件描述符。
shm_unlink():根据(shm_open() 返回的)文件描述符,删除共享内存段。实际上,这个内存段直到访问
它的所有进程都退出时才会删除,这与在 UNIX 中删除文件很相似。但是,调用 shm_unlink() (通常由原来创建共享内存段的进程调用)之后,其他进程就无法访问这个内存段了。
mmap():把共享内存段映射到进程的内存。这个系统调用需要 shm_open() 返回的文件描述符,它返回指向内存的指针。(在某些情况下,还可以把一般文件或另一个设备的文件描述符映射到内存。mmap的实现也是基于上述原理,在使用mmap映射某个文件(或者文件的一部分)到进程的地址空间时,并没有加载文件的数据,而只是在进程的虚拟地址空间划分出一块区域,标记这块区域用于映射到文件的数据区域,mmap的操作就完成了。
void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset ) 
munmap():作用与 mmap() 相反。
msync():用来让共享内存段与文件系统同步 — 当把文件映射到内存时,这种技术有用。
使用共享内存的步骤:
使用共享内存的过程是,用 shm_open() 创建内存段,用 write() 或 ftruncate() 设置它的大小,用 mmap() 把它映射到进程内存,执行其他参与者需要的操作。当使用完时,原来的进程调用 munmap() 和 shm_unlink(),然后退出。

示例程序

[cpp] view plaincopy

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/file.h>
  6. #include <sys/mman.h>
  7. #include <sys/wait.h>
  8. void error_and_die(const char *msg) {
  9. perror(msg);
  10. exit(EXIT_FAILURE);
  11. }
  12. int main(int argc, char *argv[]) {
  13. int r;
  14. const char *memname = "sample";
  15. const size_t region_size = sysconf(_SC_PAGE_SIZE);
  16. int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666);
  17. if (fd == -1)
  18. error_and_die("shm_open");
  19. r = ftruncate(fd, region_size);
  20. if (r != 0)
  21. error_and_die("ftruncate");
  22. void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  23. if (ptr == MAP_FAILED)
  24. error_and_die("mmap");
  25. close(fd);
  26. pid_t pid = fork();
  27. if (pid == 0) {
  28. u_long *d = (u_long *) ptr;
  29. *d = 0xdbeebee;
  30. exit(0);
  31. }
  32. else {
  33. int status;
  34. waitpid(pid, &status, 0);
  35. printf("child wrote %#lx\n", *(u_long *) ptr);
  36. }
  37. r = munmap(ptr, region_size);
  38. if (r != 0)
  39. error_and_die("munmap");
  40. r = shm_unlink(memname);
  41. if (r != 0)
  42. error_and_die("shm_unlink");
  43. return 0;
  44. }

以下为另外一个示例程序

点击打开链接

[cpp] view plaincopy

  1. /*-------------map_normalfile1.c-----------*/
  2. #include <sys/mman.h>
  3. #include <sys/types.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. typedef struct{
  7. char name[4];
  8. int  age;
  9. }people;
  10. main(int argc, char** argv) // map a normal file as shared mem:
  11. {
  12. int fd,i;
  13. people *p_map;
  14. char temp;
  15. fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,00777);
  16. lseek(fd,sizeof(people)*5-1,SEEK_SET);
  17. write(fd,"",1);
  18. p_map = (people*) mmap( NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,
  19. MAP_SHARED,fd,0 );
  20. close( fd );
  21. temp = ‘a‘;
  22. for(i=0; i<10; i++)
  23. {
  24. temp += 1;
  25. memcpy( ( *(p_map+i) ).name, &temp,2 );
  26. ( *(p_map+i) ).age = 20+i;
  27. }
  28. printf(" initialize over \n ");
  29. sleep(10);
  30. munmap( p_map, sizeof(people)*10 );
  31. printf( "umap ok \n" );
  32. }
  33. /*-------------map_normalfile2.c-----------*/
  34. #include <sys/mman.h>
  35. #include <sys/types.h>
  36. #include <fcntl.h>
  37. #include <unistd.h>
  38. typedef struct{
  39. char name[4];
  40. int  age;
  41. }people;
  42. main(int argc, char** argv)  // map a normal file as shared mem:
  43. {
  44. int fd,i;
  45. people *p_map;
  46. fd=open( argv[1],O_CREAT|O_RDWR,00777 );
  47. p_map = (people*)mmap(NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,
  48. MAP_SHARED,fd,0);
  49. for(i = 0;i<10;i++)
  50. {
  51. printf( "name: %s age %d;\n",(*(p_map+i)).name, (*(p_map+i)).age );
  52. }
  53. munmap( p_map,sizeof(people)*10 );
  54. }

共享内存的限制:

点击打开链接

正常大小为32M,可以通过shmmax更改~

/proc/sys/kernel/shmmax

五,信号
软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。
信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。
在进程表的表项中有一个软中断信号域,该域中每一位对应一个信号,当有信号发送给进程时,对应位置位。由此可以看出,进程对不同的信号可以同时保留,但对于同一个信号,进程并不知道在处理之前来过多少个。
信号处理函数如下

[cpp] view plaincopy

  1. void (*signal(int signo,void (*func)(int)))(int)

示例如下

[cpp] view plaincopy

  1. if(signal(SIGUSR1,sig_usr)==SIG_ERR)
  2. printf("can not catch SIG_USR1");

kill函数用来将信号发送给进程或者进程组,raise函数则允许进程向自身发送信号

[cpp] view plaincopy

  1. int kill(pid_t pid,int signo);
  2. int raise(int signo);

信号的缺点是:不能用来传输数据,一般用来在进程之间的异常通知

六:socket通信

七,文件

有点是可以共享大量的数据,缺点是共享速度慢,因为涉及到了磁盘的读写,磁盘的速度远比不上内存,另外文件本身不安全,有些特权用户可以将文件删除。

时间: 2024-11-05 06:26:15

[linux]进程(七)——进程通信的相关文章

Linux下的进程通信方式(IPC)——管道通信

Unix IPC: 管道.命名管道(FIFO)      管道 1.概念 管道是单向的(半双工).先进先出.无结构的字节流,它把一个进程的输出和另一个进程的输入连接在一起. 写进程在管道的尾端写入数据,读进程在管道的首端读出数据.数据读出后将从管道中移走,其它读进程都不能再读到这些数据. 管道提供了简单的流控制机制.进程试图读一个空管道时,在数据写入管道前,进程将一直阻塞.同样,管道已经满时,进程再试图写管道,在其它进程从管道中读走数据之前,写进程将一直阻塞. 2.管道的特点 (1)单向数据通信

Linux 线程与进程,以及通信

http://blog.chinaunix.net/uid-25324849-id-3110075.html 部分转自:http://blog.chinaunix.net/uid-20620288-id-3025213.html 1.首先要明确进程和线程的含义: 进程(Process)是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位.与程序相比,程序只是一组指令的有序集合,它本身没有任何运行的含义,只是一个静态实体.进程是程序在某个数据集上的执行,

linux 进程间的通信

现在linux使用的进程间通信方式:(1)管道(pipe)和有名管道(FIFO)(2)信号(signal)(3)消息队列(4)共享内存(5)信号量(6)套接字(socket) 为何进行进程间的通信:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到.C.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程).D.资源共享

Linux进程间的通信

一.管道 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: A. 管道是半双工的,数据只能向一个方向流动: B. 需要双工通信时,需要建立起两个管道: C. 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程): D. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中. 匿名管道的创建:该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义;因此,一

Linux间的进程通信;以及子进程的创建

1 "-----第六天-----------------------------------------------------------------------------" 2 3 1.版本控制:svn/git; 4 5 2.进程的概念: 6 1)程序和进程: 7 每个进程操作系统会为它分配 0-4G 的虚拟内存空间(32位操作系统): 其中0-3G为用户内存空间,进程可以对它进行读写操作: 3G - 4G 为系统内核空间,进程没有读写权限. 8 进程只能读写用户空间,没有权限读

Linux进程间的通信方法

linux进程间的通信方法总结如下 通过fork函数把打开文件的描述符传递给子进程 通过wait得到子进程的终结信息 通过加锁的方式,实现几个进行共享读写某个文件 进行间通过信号通信,SIGUSR1和SIGUSR2实现用户定义功能 利用pipe进行通信 FIFO文件进行通信 mmap,几个进程映射到同一内存区 SYS IPC 消息队列,信号量(很少用) UNIX Domain Socket,常用

Linux系统编程@进程通信(一)

进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统的一个分支) POSIX进程间通信(POSIX:可移植操作系统接口,为了提高UNIX环境下应用程序的可移植性.很多其他系统也支持POSIX标准(如:DEC OpenVMS和Windows).) 现在Linux使用的进程间通信方式包括: 管道(pipe).有名管道(FIFO) 信号(signal) 消

Linux/UNIX进程间的通信(1)

进程间的通信(1) 进程间的通信IPC(InterProcessCommunication )主要有以下不同形式: 半双工管道和FIFO:全双工管道和命名全双工管道:消息队列,信号量和共享存储:套接字和STREAMS 管道 pipe函数 当从一个进程连接到另一个进程时,我们使用术语管道.我们通常是把一个进程的输出通过管道连接到另一个进程的输入. 管道是由调用pipe函数创建的: #include<unistd.h> int pipe(intpipefd[2]); 经由参数pipefd返回两个文

Linux环境编程之进程(七):守护进程

守护进程也是一种进程,它由如下特性: 1.生存期较长,在系统自举时启动,仅在系统关闭时终止. 2.没有控制终端,在后台运行. 系统中有很多守护进程,它们执行日常事务活动.如日志进程syslogd.web服务器httpd.邮件服务器sendmail和数据块服务器mysqld等.大多数守护进程都是以超级用户(用户ID为0)特权运行.没有一个守护进程具有控制终端,其终端设置为问号(?),终端前台进程组ID设置为-1.内核守护进程以无控制终端方式启动.用户层守护进程缺少控制终端可能是守护进程调用了set

Linux/UNIX之进程间的通信(2)

进程间的通信(2) 有三种IPC我们称为XSI IPC,即消息队列.信号量以及共享存储器,它们之间有很多相似之处. 标识符和键 每个内核的IPC结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符加以引用.例如,为了对一个消息队列发送或取消息,只需要知道其队列标识符.与文件描述符不同,IPC标识符不是小的整数.当一个IPC结构被创建,以后被删除时,与这种结果相关的标识符连续加1,知道达到一个整型数的最大值,然后又回到0. 标识符是IPC对象的内部名.为使多个合作进程能够在同一IPC对象上