一、什么是进程间通信
进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。但是,系统空间却是“公共场所”,所以内核显然可以提供这样的条件。除此以外,那就是双方都可以访问的外设了。在这个意义上,两个进程当然也可以通过磁盘上的普通文件交换信息,或者通过“注册表”或其它数据库中的某些表项和记录交换信息。广义上这也是进程间通信的手段,但是一般都不把这算作“进程间通信”。
二、信号量在进程间通信方式
信号(Signals )是Linux系统中使用的最古老的进程间通信的方法之一。 操作系统通过信号来通知进程系统中发生了某种预先规定好的事件(一组事件中的一个),它也是用户进程之间通信和同步的一种原始机制。一个键盘中断或者一个错误条件(比如进程试图访问它的 虚拟内存中不存在的位置等)都有可能产生一个信号。Shell也使用信号向它的子进程发送 作业控制信号。
1、临界资源
同一时刻只允许一个进程访问的资源叫临界资源。
2、临界区
访问临界资源的代码即是临界区。
3、原子操作
通过P、V操作来控制同步进程。
4、下面是几个常见的信号。
SIGHUP: 从 终端上发出的结束信号;
SIGINT: 来自键盘的中断信号(Ctrl-C);
SIGQUIT:来自键盘的退出信号(Ctrl-\);
SIGFPE: 浮点异常信号(例如 浮点运算溢出);
SIGKILL:该信号结束接收信号的进程;
SIGALRM:进程的定时器到期时,发送该信号;
SIGTERM:kill 命令发出的信号;
SIGCHLD:标识子进程停止或结束的信号;
SIGSTOP:来自键盘(Ctrl-Z)或调试程序的停止执行信号;
…………
三、创建初始化、P、V、销毁信号量操作代码
#include "sem.h"
static int semid = -1;
void sem_init()
{
semid = semget((key_t)1234,1,IPC_CREAT | IPC_EXCL | 0600);
if(semid == -1)
{
semid = semget((key_t)1234,1,0600);
if(semid == -1)
{
perror("semget error");
return ;
}
}
else
{
union semun a;
a.val = 1;
if(semctl(semid,0,SETVAL,a)== -1)
{
perror("semctl error");
}
}
}
void sem_p()
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op =-1;
buf.sem_flg =SEM_UNDO;
if(semop(semid,&buf,1)== -1)
{
perror("semop p error");
}
}
void sem_v()
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1)== -1)
{
perror("semop v error");
}
}
void sem_destroy()
{
if(semctl(semid,0,IPC_RMID)== -1)
{
perror("semtcl error");
}
}
4、简单使用信号量来进行同步进程
代码测试目的是为了在三个进程下,通过同步进程来按顺序连续输出abc,最后输出的abc不会颠倒顺序。
a进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/sem.h>
#include "sem.h"
int main()
{
sem_init();
int i=0;
for(;i<5;i++)
{
sem_p();
write(1,"A",1);
int n=rand() %3;
sleep(n);
write(1,"A",1);
sem_v();
int s=rand() %3;
sleep(s);
}
}
b进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/sem.h>
#include "sem.h"
int main()
{
sem_init();
int i=0;
for(;i<5;i++)
{
sem_p();
write(1,"B",1);
int n=rand() %3;
sleep(n);
write(1,"B",1);
sem_v();
int s=rand() %3;
sleep(s);
}
}
c进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/sem.h>
#include "sem.h"
int main()
{
sem_init();
int i=0;
for(;i<5;i++)
{
sem_p();
write(1,"C",1);
int n=rand() %3;
sleep(n);
write(1,"C",1);
sem_v();
int s=rand() %3;
sleep(s);
}
sleep(10);
sem_destroy();
}
最后的c进程在睡眠10秒后通过调用sem_destroy()来进行销毁。最后输出结果为连续的5个ABC,达到成功完成实验的结果。