进程间通信的作用:数据传输; 资源共享; 通知事件; 进程控制。
管道通信
管道是单向的,先进先出(FIFO)。将一个进程的输出和另一个进程的输入连在一起。输出进程在管道尾部写入数据,输入进程在管道头部接受数据。数据在被读出后,将从管道中清楚,其他进程再也无法读取到该数据。进程试图读空管道时,进程将阻塞。同样,管道已经满时,进程再试图向管道写入数据,进程将阻塞。管道分为无名管道和有名管道。无名管道适用于父子进程; 有名管道适用于任意两个进程。无名管道(PIPE)创建:
int pipe(int filedis[2]);
当一个管道建立时,它会创建两个文件描述符:
filedis[0] 用于读管道,
filedis[1] 用于写管道。管道用于不同进程间通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道。
有名管道(FIFO)创建: int mkfifo(const char * pathname, mode_t mode);
该函数会依据pathname创建一个特殊的FIFO文件,该文件必须是不存在的,而参数mode是该文件的权限。
信号通信命令:kill -l 可以列出全部信号(signal)。下面是几种常见的信号:
SIGHUP: 从终端上发出的结束信号
SIGINT: 来自键盘的中断信号(Ctrl-C)
SIGKILL:该信号结束接收信号的进程
SIGTERM:kill 命令发出的信号
SIGCHLD:标识子进程停止或结束的信号
SIGSTOP:来自键盘(Ctrl-Z)或调试程序的停止执行信号当一个信号出现时,会以三种方式进行处理:1.忽略此信号,大多数信号用这种方式处理,除了SIGKILLSIGSTOP,因为这两个信号向超级用户提供了一种终止或停止进场的方法;2.执行用户希望的动作,通知内核在某种信号发生时,调用一个用户函数。在用户函数中,执行用户希望的处理;3.执行默认的操作,对大多数信号的系统默认动作是终止该进程。发送信号的主要函数有kill和raise。Kill既可以向自身发送信号,也可以向其他进程发送信号。与kill函数不同的是,raise函数是向进程自身发送信号。
int kill(pid_t pid, int signo);//向pid进程发送signo
int raise(int signo);//向自己发送signo
共享内存共享内存是被多个进程共享的一部分物理内存。共享内存是进程间共享数据的一种最快的方法。
实现共享内存的步骤:1.创建共享内存(物理内存),shmid = shmget(key_t key, int size, int shmflg );2.将共享内存映射到进程的虚拟内存中,shmadd = shmat(int shmid, char *shmaddr, int flag);flag通常为‘0’;3.使用映射的内存;4.接触映射,shmdt(char *shmaddr);5.销毁共享内存,shmctl(int shmid);消息队列
消息队列就是一个消息的链表.可以把消息看作一个记录,具有特定的格式.进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息。
目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。
系统V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除。
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值。创建消息队列#define MSGKEY 1212
int msgid;
msgid = msgget(MSGKEY, IPC_CREAT | IPC_EXCL);//以1212为键值,创建一个消息队列,若已存在,则无法再创建
打开消息队列msgid = msgget(MSGKEY, 0);//打开键值为MSGKEY的消息队列
发送信息struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[100]; /* message data */
};//消息队列中传输的结构体类型,包括两个部分,一个是数据类型type,一个是内容
int msgid, ret;
struct msgbuf mbuf;
memset(&mbuf, 0, sizeof(mbuf));
scanf("%s", mbuf.mtext);
mbuf.mtype = 1;//设置消息类型为1
ret = msgsnd(msgid, &mbuf, sizeof(mbuf.mtext), 0);//将mbuf结构体中的内容发送到以msgid为描述字的消息队列中
if (-1 == ret)//若发送失败则返回-1
{
perror("msgsnd");
exit(1);
}
接收消息ret = msgrcv(msgid, &mbuf, sizeof(mbuf.mtext), 1, 0);//接收type为1的消息,与发送来的信息类型相对应
if (-1 == ret)
{
perror("msgrcv");
exit(1);
}
信号灯
信号量(又名:信号灯)与其他进程间通信方式不大相同,主要用途是保护临界资源(一次只允许一个进程访问的资源)。
二值信号灯:信号灯的值只能取0或1,类似于互斥锁。 但两者有不同:信号灯强调共享资源,只要共享资源可用,其他进程同样可以修改信号灯的值;互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁。