进程间通信
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