linux进程通信

e14: 进程间通信(进程之间发送/接收字符串/结构体):

传统的通信方式:

管道(有名管道 fifo,无名管道 pipe)

信号 signal

System V(基于IPC的对象):                             IPC对象:                                                    ipcrm [ -M key | -m id | -Q key | -q id | -S key | -s id ] ...

消息队列 message queue                              ipcs:                                                       ipcrm {shm|msg|sem} id...

共享内存 share memory                                    -m     shared memory segments

信号量集/信号灯集 semaphore                              -q     message queues

-s     semaphore arrays

-a     all (this is the default)

----------------------------------------------------------------------------

| System V的流程:                                                       |                                  system() - execute a shell command

|   已经存在的路径名---->ftok()---->key---->IPC对象---->id---->使用      |                                    调用/bin/sh -c command,执行命令command

|                                                                          |

|    key-----shmget(),msgget(),semget()----->IPC对象(id号)             |

|        eg:key=ftok("/",‘a‘);                                             |

|           id=msgget(key,IPC_CREAT|0666);                                 |

|           open(filename,O_CREAT,0666);                                   |

----------------------------------------------------------------------------

BSD:

套接字 socket

e14-1: 无名管道pipe(用于具有亲缘关系的进程,单向的数据传输通道):

int pipe(int pipefd[2]);

pipefd[0]----读端,pipefd[1]----写端

----------------------------------------------------------------------

读端:

写端存在:

管道是有数据的,返回读取的字节数

管道是没有数据的,阻塞/等待直到管道中有数据

写端不存在:

管道是有数据的,返回读取的字节数

管道是没有数据的,返回0

写端:

读端存在:

管道有空间,返回写入的字节数

管道没有空间/空间不足,有多少写多少,直到写完返回

读端不存在:

进程被终止

e14-2: 有名管道fifo(first in first out)(用在独立的进程之间,双向的):

有名管道是独立于进程存在的

有名管道可以看成由文件名标识的一根管道

创建:mkfifo

删除:unlink

监听:open(O_RDONLY)

开始会话:open(O_WRONLY)

两个进程通过FIFO进行通信:发送----write

接收----read

结束通信:close

----------------------------------------------------------------------

关于阻塞:

读端:open(O_RDONLY);写端:open(O_WRONLY)

只有读端或者只有写端的时候,open调用会阻塞

验证方法:只运行read或者write程序

写端关闭:只剩下读端时,read立即返回0

读端关闭:只剩下写端时,写端会被终止

O_RDWR:两端都是O_RDWR方式打开时,两端都运行。如果一端退出,因为另一端以O_RDWR的方式打开,相当与自己也可以写,自己也可以读,在调用read,write时会阻塞

----------------------------------------------------------------------------------

多个进程读fifo:有名管道是一个队列,而不是常规文件。写端将字节写入队列,读端从队列的头部移出字节,每个读端都会将数据移出队列。所以如果想要保证读端都读到数据,写端必须要重写数据。

----------------------------------------------------------------------------------

竞态条件:FIFO不会出现竞态条件的问题。read和write系统调用是原子操作。读取操作将管道清空,而写入操作又将管道塞满。在读端和写端连通之前,系统内核会将进程挂起。

e14-3: 消息队列message queue:

key-----msgget()----->IPC对象(id号)

eg: 创建:key=ftok("/",‘a‘);

id=msgget(key,IPC_CREAT|0666);

open(filename,O_CREAT,0666);

删除:msgctl:IPC_RMID

发送:msgsnd

接收:msgrcv

e14-4: 共享内存share memory:

最快速的进程间通信方式,适合大量数据的传输。他是一种高效率的进程间通信方式,进程可以直接读写内存空间,而不需要任何数据的copy

交互的时候不妨便,尤其是复杂的交互程序,需要同步/互斥

--------------------------------------------------------------------------------------------------------------------------------

共享内存的实现分为两个步骤:创建共享内存;映射共享内存,解除映射

创建/打开:shmget

删除:shmctl:IPC_RMID

内存映射:shmat:shmaddr--->内存映射指定的地址,若是NULL,表示由系统自动映射

shmflg---->默认是0,共享内存可读写,若是SHM_RDONLY,表示共享内存只读

内存解除映射:shmdt

e14-5: 信号量集/信号灯集semaphore:

信号量是一个内核变量,它可以被系统当中的任何进程所访问

进程之间可以使用这个变量来协调对于共享内存和其他资源的访问

信号量集是一个或多个信号量的一个集合,其中的每一个元素都是单独的信号量

信号量集机制------>解决进程间的同步与互斥

创建:semget

删除:semctl:IPC_RMID

初始化:semctl:SETVAL

修改:semop:sops---->结构体数组的首地址

nsops---->结构体数组的大小

结构体:struct sembuf{

unsigned short sem_num;  /* semaphore number */

short          sem_op;   /* semaphore operation */

short          sem_flg;  /* operation flags */

};

sem_op:

>0   对信号量的当前值进行增加

=0   等待直到信号量的值为0

<0   对信号量的当前值进行减少(如果不够减,就会等待)

sem_flag:SEM_UNDO,在进程终止前,对信号量进程恢复

e14-6: 信号signal:

信号来自内核

发送信号的方式:

1.键盘快捷键

2.内核在执行程序出错时。比如:非法段存取,浮点数溢出或除零运算

3.一个进程可以通过系统调用给另一个进程发送信号

特点:信号是一种异步通信方式,唯一的一种异步通信方式

信号可以直接进行用户空间过程和内核空间进程的交互

内核空间进程可以用信号来通知用户空间进程发生了哪些系统事件

------------------------------------------------------------------------------------------------------

用户空间进程对信号的响应方式:

1.忽略信号:对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL(9) 和STGSTOP(10)

2.捕捉信号:定义信号处理函数,当信号发生时,执行相对应的信号处理函数

3.执行默认操作:linux对每种信号都规定了默认操作

--------------------------------------------------------------------------------------------------------

信号(kill -l):

1.SIGHUP(终止进程):

在用户终端连接结束的时候发出的,通常是终端的控制进程结束时,通知同一会话的各个进程组与控制终端不再连接

2.SIGINT(终止进程):

用户输入“ctrl + c”时发出,前台进程中的每一个进程会接收到这个信号

3.SIGQUIT(终止进程):

用户输入“ctrl + \”时发出

9.SIGKILL(终止进程):

立即结束程序的运行,不能被忽略

14.SIGALRM(终止进程):

当一个定时器到时的时候发送

===============================================================================================

| sleep:添加延时                                                                             |

| sleep(n)----将当前进程挂起n秒                                                               |

|    1.为SIGALRM设置处理函数                                                                  |

|    2.调用alarm(num_seconds):设置一个定时器,在num_seconds秒之后发送SIGALRM信号           |

|       alarm也叫做闹钟函数,如果之前有设置定时器,前面设置的会失效                           |

|    3.pause():挂起进程直到信号到达,任何的信号都可以唤醒进程                              |

===============================================================================================

| usleep:实现精度更高的延时                                                                  |

|    int usleep(useconds_t usec);                                                             |

|                                                                                             |

|  获取或设置间隔计时器:                                                                     |

|   int getitimer(int which, struct itimerval *curr_value);                                   |

|   int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);  |

|                                                                                             |

|      which:获取或设置的计时器                                                              |

|           ITIMER_REAL:真实----------发送 SIGALRM                                           |

|           ITIMER_VIRTUAL:虚拟-------------发送 SIGVTALRM                                   |

|           ITIMER_PROF:实用----------发送 SIGPROF                                           |

|      struct itimerval 结构体                                                                |

|           struct itimerval {                                                                |

|   struct timeval it_interval; /* next value */                                  |

| struct timeval it_value;    /* current value */                               |

| };                                                                                |

|      struct timeval {                                                                       |

|           long tv_sec;                /* seconds */                                         |

|     long tv_usec;               /* microseconds */                                    |

|      };                                                                                     |

|                                                                                             |

|               tv_sec                  tv_usec                                               |

|       ----------------------------------------------                                        |

|    it_valuse    |                       |                (初始时间)                       |

|    it_interval  |                       |                (间隔时间)                       |

===============================================================================================

17.SIGCHLD(忽略):

子进程改变状态的时候,父进程会收到这个信号

19.SIGSTOP(暂停进程,不消灭进程):

用于暂停一个进程,且不能被忽略,不能定义处理函数

20.SIGTSTP(暂停进程,不消灭进程):

用于暂停交互进程,用户输入“ctrl + z”发出信号

----------------------------------------------------------------------------------------------------------------

信号的处理函数的注册/关联/定义:

sighandler_t signal(int signum, sighandler_t handler);

signum:需要相应的信号

handler:如何相应/信号处理函数----SIG_DFL(将信号恢复为默认处理) or SIG_IGN(忽略信号)

-----------------------------------------------------------------------------------------------------------------

处理信号的流程:

一个正常的控制流/代码流,从main函数开始执行,然后从main函数返回另一个控制流/代码流,它是由信号引起的一个路径,进入信号处理函数,然后返回到调用它的代码中

-------------------------------------------------------------------------------------------------------------------

信号的发送:

kill():给进程或进程组发送一个信号  int kill(pid_t pid, int sig);   pid----正数,要接收信号的进程的pid                              sig:信号的编号

kill命令是kill函数的一个用户接口                                         ----0,信号被发送到所有和调用pid进程在统一个进程组的进程

raise():允许进程给自己发送信号                                        ---- -1,给所有的有权限的进程发送信号

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

signal 出现的问题:

信号排队:等待阻塞

信号处理函数被打断,信号嵌套,递归

不可靠的信号

对信号的操作/处理的3种方法:

1.递归

2.忽略

3.阻塞/等待

sigaction------指定什么信号将被如何处理/指定一个信号的处理函数

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

signum----> 要处理的信号

act----> 指针,指向描述操作的结构 / 指向描述如何响应信号的结构

oldact----> 指针,指向描述被替换操作的结构 / 指向描述被替换的处理设置的结构

struct sigaction {

void     (*sa_handler)(int); --------->   跟signal类似,使用旧处理方式(SIG_DFL,SIG_IGN,处理函数)

void     (*sa_sigaction)(int, siginfo_t *, void *); ---------->  新的方式,不但可以得到信号编号,还可以获取被调用的原因以及产生问题的上下文

sigset_t   sa_mask; ---------------->  决定在处理一个信号的函数时,是否要阻塞其他信号。sa_mask 的值包括要被阻塞的信号的集合

int        sa_flags; ------->SA_RESETHAND:当处理函数被调用时会进行重置     SA_RESTART:当系统调用是针对一些慢速的设备或类似的系统调用,重新开始而不是返回

void     (*sa_restorer)(void);

};

一个 sigset_t 是一个抽象的信号量,可以通过一些函数来添加,删除信号的

int sigemptyset(sigset_t *set);   // 清除由set指向的集合中的所有信号

int sigfillset(sigset_t *set);    //添加所有的信号到set指向的集合

int sigaddset(sigset_t *set, int signum);    //添加signum到set指向的集合

int sigdelset(sigset_t *set, int signum);    //从set指向的集合中删除signum所标识的信号

======================================================================================================================================================================

临界区:

一段修改一个数据结构的代码,如果在运行时被打断将导致数据的不完整或损坏,那么称这段代码为临界区

阻塞信号:sigprocmask

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);   修改当前的信号掩码/屏蔽字

how------> 如何修改   SIG_BLOCK:添加    SIG_UNBLOCK:删除    SIG_SETMASK:替换/设置

set------> 指向使用的信号集

oldset---------> 指向之前的信号掩码/NULL

*******************************************************************************************************

eg:暂时的阻塞 SIGINT 和 SIGQUIT 信号

sigset_t sigs,prevsigs;

sigemptyset(&sigs);   //清空

sigaddset(&sigs,SIGINT);   //添加

sigaddset(&sigs,SIGQUIT);

sigprocmask(SIG_BLOCK,&sigs,&prevsigs);   //添加阻塞信号

//操作数据结构

sigprocmask(SIG_SETMASK,&prevsigs,NULL);   //恢复之前的prevsigs

e14-7: 套接字socket:

============================================================================================================================

|                                                                                                                          |

|  进程间通信方式总结:                                                                                                    |

|                                                                                                                          |

|     无名管道pipe:          具有亲缘关系的进程间进行使用,单向                                                           |

|                                                                                                                          |

|   有名管道fifo:          可以用在任意的进程之间,双向,有文件名                                                       |

|                                                                                                                          |

|   信号signal:            异步,不需要等待                                                                             |

|                                                                                                                          |

|   消息队列msgq:          消息是有类型的                                                                               |

|                                                                                                                          |

|   共享内存share memory:  效率最高,需要同步/互斥机制                                                                  |

|                                                                                                                          |

|   信号量集semaphore:     需要配合共享内存或者公共资源使用,可以实现同步/互斥机制,但是不能单独用于进程间信息的传递    |

|                                                                                                                          |

|   套接字socket:          可以跨主机进行进程间通信                                                                     |

|                                                                                                                          |

============================================================================================================================

时间: 2024-10-07 05:21:33

linux进程通信的相关文章

Linux 进程通信之 ——信号和信号量总结

如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存.       所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一样.通信是一个广义上的意义,不仅仅指传递一些massege.他们的用法是基本相同的,所以仅仅要掌握了一种的用法,然后记住其他的用法就能够了. 1. 信号       在我学习的内容中,主要接触了信号来实现同步的机制,据说信号也能够用来做其他的事      情,可是我还不知道做什么.       信号和信号量是

浅析linux进程通信的方式

求职笔试中,考察进程通信方式是一个老生长谈的问题,每次都让我答得一头雾水,于是我总结了一下 这些必须了解的知识点. 实现linux进程通信的方式有6种: --内存共享 --信号(Singal) --管道(Pipe) --消息队列(Message) --信号量(Semaphore) --socket 消息队列通信 请关注:http://blog.csdn.net/ljianhui/article/details/10287879 内存共享通信 请关注:http://blog.csdn.net/lj

linux进程通信之SYSTEM V信号量

信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有.信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒. 一.信号量的分类: 在学习信号量之前,我们必须先知道--Linux提供两种信号量: (1) 内核信号量,由内核控制路径使用. (2) 用户态进程使用的信号量,这种信号量又分为POSIX信号量和SYSTEM V信号量. POSIX信号量又分为有名信号量和无名信号量.有名信号量,其值保存在文件

Linux进程通信----匿名管道

Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组 表示的文件描述字.这个数组有两个文件描述字,第一个是用 于读数据的文件描述符第二个是用于写数据的文件描述符. 不能将用于写的文件描述符进行读操作或者进行读的文件描述 符进写操作,这样都会导致错误. 关于匿名管道的几点说明: 1.匿名管道是半双工的,即一个进程只能读,一个进程只能写    要实现全双工,需要两个匿名管道. 2.只能在父子进程或者兄弟进程进行通信. 3.在读的时候关闭写文件描

Linux进程通信——管道

进程间通信(IPC:Inner Proceeding Communication) 进程是操作系统实现程序独占系统运行的假象的方法,是对处理器.主存.I/O设备的抽象表示.每个进程都是一个独立的资源管理单元,每个进程所看到的是自己独占使用系统的假象,因此各个进程之间是不能够直接的访问对方进程的资源的,不同的进程之间进行信息交互需要借助操作系统提供的特殊的进程通信机制. 进程之间的通信,从物理上分,可以分为同主机的进程之间的通信和不同主机间的进程之间的通信.从通信内容方式上分,可以分为数据交互.同

Linux笔记--Linux进程通信

Linux进程间通信 文章来源: http://www.cnblogs.com/linshui91/archive/2010/09/29/1838770.html 一.进程间通信概述进程通信有如下一些目的:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到.C.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程).D.

Linux进程通信的几种方式总结

进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程). 资源共享 多个进程之间共享同样的资源.为了作到这一点,需要内核提供锁和同步机制. 进程控制 有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变.

linux 进程通信之 共享内存

共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容. 关于共享内存使用的API key_t ftok(const char *pathname, int proj_id); #在IPC中,我们经常用一个 key_t 的值来创建或者打开 信号量,共享内存和消息队列.这个 key_t 就是由ftok函数产生的. pathname:指定的文件名,该文件必须是存在而且可以访问 proj_

linux进程通信之管道

1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用一个进程的标准输出作为另一个进程的标准输入建立的一个单向管道,执行完成后消失.主要用于父进程与子进程之间,或者两个兄弟进程之间.采用的是单向 1)创建无名管道:(#include(unistd.h)) extern int pipe(int pipes[2]),pipes[0]完成读操作,pipes