[Linux C编程]进程间通信

时间:2021-05-17 14:56:54

进程间通信

1.管道有什么特点?

管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。

一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。

数据被一个进程读出后,将被从管道中删除,其它读进程将不能再读到这些数据。

管道提供了简单的流控制机制,进程试图读空管道时,进程将阻塞。同样,管道已经满时,进程再试图向管道写入数据,进程将阻塞

2.无名管道与有名管道的区别?

无名管道:用于父进程和子进程间的通信

有名管道:用于运行同一系统中的任意两个进程间的通信。

3.无名管道的操作

创建管道pipe

读管道read

写管道write

关闭管道close

(1)pipe

函数的原型:int pipe(int fds[2])

函数的参数:新建的两个描述符fds数组,fds[0]表示管道的读取端,fds[1]表示管道的写入端。

头文件:#include <unistd.h>

返回值:成功返回0  出错返回-1

4.无名管道读写:

先创建管道pipe

fork创建子进程:(管道用于不同进程间通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道)

(1)管道通讯是单向的,有固定的读端和写端。

(2)数据被进程从管道读出后,在管道中该数据就不存在了。

(3)当进程去读取空管道的时候,进程会阻塞。

(4)当进程往满管道写入数据时,进程会阻塞。

(5)管道容量为64KB

5.有名管道操作:

创建管道mkfifo

打开管道open

读管道read

写管道write

关闭管道close

删除管道unlink

(1)mkfifo

函数的作用:创建一个有名管道

函数的原型:int mkfifo(const char * pathname,mode_t mode)

参数的作用:pathname:FIFO的路径名称

        mode:打开管道的方式

           O_NONBLOCK:非阻塞

           O_RDONLY:只读

           O_WRONLY:只写

           O_RDWR:可读写

6.管道使用和文件操作的区别?

(1)读取fifo文件的进程只能以”RDONLY”方式打开fifo文件。

(2)写fifo文件的进程只能以”WRONLY”方式打开fifo

(3) fifo文件里面的内容被读取后,就消失了。但是普通文件里面的内容读取后还存在。

7.什么是信号机制?

信号(signal)机制是Unix系统中最为古老的进程间通信机制,很多条件可以产生一个信号:

(1)当用户按某些按键时,产生信号

(2)硬件异常产生信号:除数为0、无效的存储访问等等。这些情况通常由硬件检测到,将其通知内核,然后内核产生适当的信号通知进程,例如,内核对正访问一个无效存储区的进程产生一个SIGSEGV信号

(3)进程用kill函数将信号发送给另一个进程

(4)用户可用kill命令将信号发送给其他进程

8.有哪几种常见的信号?

下面是几种常见的信号:

§ SIGHUP: 从终端上发出的结束信号

§ SIGINT: 来自键盘的中断信号(Ctrl-C)

§ SIGKILL:该信号结束接收信号的进程,杀死进程

§ SIGTERM:kill 命令发出的信号

§ SIGCHLD:子进程停止或结束时通知父进程

§ SIGSTOP:来自键盘(Ctrl-Z)或调试程序的停止执行信号,暂停进程

9.信号处理的三种方式是什么?

1、忽略此信号

   大多数信号都按照这种方式进行处理,但有两种信号决不能被忽略,它们是:

SIGKILL\SIGSTOP。这两种信号不能被忽略的原因是:它们向超级用户提供了一种终止或停止进程的方法

2、执行用户希望的动作

通知内核在某种信号发生时,调用一个用户函数。在用户函数中,执行用户希望的处理

3、执行系统默认动作

对大多数信号的系统默认动作是终止该进程

10.信号的发送,捕获,处理如何操作?用什么函数实现?

(1)kill

函数的作用:传递信号给指定的进程

函数的原型:int kill(pid_t pid,int sig)

函数的参数:pid > 0:指定的进程pid

        pid == 0:将信号发送给同组的进程

        pid < 0: 将信号发送给其进程组ID等于pid绝对值的进程

        pid == -1:将信号发送给所有进程

头文件:#include <sys/types.h>

     #include <signal.h>

(2)raise

函数的作用:发送信号给自身

函数的原型:int raise(int sig)

头文件:#include <signal.h>

kill与raise的区别:

kill既可以向自身发送信号,也可以向其他进程发送信号

raise:是向进程自身发送信号

(3)alarm

函数的作用:设置信号传送闹钟

函数的原型:unsigned int alarm(unsigned int seconds)

头文件:#include <unistd.h>

返回值:返回之前闹钟的剩余秒数,如果之前未设闹钟则返回0

(4)pause

函数的作用:让进程暂停,直到信号出现

函数的原型:int pause(void)

(5)signal

函数的作用:设置信号的处理方式

函数的原型:void (*signal(int signo,void (*sighandler_t)(int)))(int)

typedef void (*sighandler_t)(int) sighandler_t

signal(int signum, sighandler_t handler))

func可能的值是:

(1)SIG_IGN:忽略此信号

(2)SIG_DFL: 按系统默认方式处理

(3)信号处理函数名:使用该函数处理

11.什么是共享内存?

共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容.

12.如何实现共享内存?

(1)创建共享、打开共享内存,使用shmget函数

(2)映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数

(3)分离共享内存

(4)控制、删除共享内存

 

(1)shmget

函数的作用:在内核中创建共享内存

函数的原型:int shmget ( key_t key, int size, int shmflg )

函数的参数:key:标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,

则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数

shmflg中又设置IPC_PRIVATE这个标志,则同样会创建一块新的共享内存。

            size:创建的内存的大小

            shmflg:类似open权限

返回值:成功:返回共享内存标识符,出错:-1

头文件:#include<sys/ipc.h>

     #include<sys/shm.h>

(2)shmat

函数的作用:映射共享内存,映射到各自的内存空间

函数的原型:char * shmat ( int shmid, char *shmaddr, int flag)

函数的参数:shmid:内存标识符

        shmaddr:映射到共享内存到本进程的指定地址,如果为NULL,则又内核自动分

        flag:决定以什么方式来确定映射的地址(通常为0)

返回值:成功:发挥共享内存映射到进程中的地址, 失败-1

(3)shmdt

函数的作用:撤销共享内存的映射

函数的原型:int shmdt(const void* shmaddr)

函数的参数:shmaddr:被映射的共享内存的地址

返回值:成功:0  出错:-1

13.什么是消息队列?

消息队列就是一个消息的链表.可以把消息看作一个记录,具有特定的格式.进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息。

14.消息队列的操作:

创建打开消息队列msgget()

读数据从队列msgrcv()

写数据到队列msgsnd()

控制消息队列msgctl()

 

(1)ftok

函数的作用:获取文件名对应的键值

函数的原型:key_t ftok (char*pathname, char proj)

函数的参数:pathname:文件名

        proj:项目名(不为0即可)

返回值:成功:返回文件名对应的键值,出错:-1

头文件:#include <sys/types.h>

     #include <sys/ipc.h>

(2)msgget

函数的作用:创建消息队列

函数的原型:int msgget(key_t key,int msgflg)

函数的参数:key:键值,由ftok获得

        msgflg:标志位

返回值:成功:消息队列的ID,出错:-1

头文件:#include<sys/types.h>

     #include <sys/ipc.h>

     #include <sys/msg.h>

(3)msgsnd

函数的作用:写数据到消息队列

函数的原型:int msgsnd(int msgid,struct msgbuf* msggp,int msgsz,int msgflg)

函数的参数:msggp:消息结构

        struct msgbuf{

          long msgtype;消息类型

          char mtext[];消息正文

        };

msgsz:消息的字节数

msgflg:IPC_NOWAIT:写不进消息,直接退回

     0:一直等待到能写进去消息为止

返回值:成功:0 出错:-1

头文件:#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

(4)msgrcv

函数的作用:从消息队列接收消息

函数的原型:int msgrcv(int msqid, struct msgbuf *msgp, int   msgsz, long msgtyp, int msgflg)

返回值:成功:0,出错:-1

(5)msgctl

函数的作用:控制消息队列,可以删除消息队列

函数的原型: int msgctl(int msgid,int cmd,struct msgid_ds * buf)

函数的参数:msgid:消息队列的ID

        cmd: IPC_STAT:读取消息队列的结构,存储在buf中

           IPC_SET:设置队列的权限

           IPC_RMID:删除消息队列

        buf:消息队列的结构类型

返回值:成功:0,出错:-1

 

15.信号量的有什么作用?

·可以保护临界资源

·进程可以根据信号量判定是否能够访问某些共享资源。除了访问控制外,还可用于进程同

16.信号量的分类?

·二值信号灯:信号灯的值只能取0或1,类似于互斥锁。但两者有不同:

(1)信号灯强调共享资源,只要共享资源可用,其他进程同样可以修改信号灯的值

(2)互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁

·计数信号灯:信号灯的值可以取任意非负值。

17.信号量的操作?

1.创建打开信号量,semget()

2.初始化信号量,semctl()的SETVAL操作。当使用二维信号量时将信号量初始化为1;

3. 进行信号量的PV操作,调用semop()函数。

4.如果不用信号量,从系统中删除他/她,使用semctl的IPC_RMID操作。

(1)semget

函数的作用:创建信号量

函数的原型:int semget(key_t key,int nsems,int semflg)

函数的参数:nsems:信号量的数目,通常取1个

        semflg:同open函数权限位

返回值:成功:信号量的标识符  错误:-1

(2)semctl

函数的作用:信号量的控制、初始化、删除

函数的原型:int semctl(int semid,int semnum,int cmd,union semun arg)

函数的参数:semnum:通常为0,第一个信号量

        cmd: IPC_STAT:

           IPC_SETVAL:设置为为arg终的val的值

           IPC_GETVAL:获取信号量的值

           IPC_RMID:删除信号量

返回值:成功: cmd不同,返回值也不同

        IPC_STAT、IPC_SETVAL、IPC_RMID:返回0

        IPC_GETVAL:返回值信号量的值

    出错 -1

(3)semop

函数的作用:执行PV操作

函数的原型:int semop(int senid,struct sembuf *sops,size_t nsops)

函数的参数:struct sembuf * sops:

        sem_op:-1  P操作

             +1  V操作

        nsops:-1

返回值:成功:信号量标识符,出错:-1