进程作为linux系统中分配资源的最小单位,进程间到协作和通信用的范围比较广泛。 进程间通信的方法有以下几种:
PIPE主要是用在父子进程之间到通信,是最初级的IPC通信方式,它主要是调用pipe()函数来生成管道,它返回两个文件描述符fd[0],fd[1],fd[0]是读端口,fd[1]是写端口,当你要用到写端口时候就必须把读端口关闭,反之亦然。PIPE是阻塞性质到,当你发送到东西大于128K到时候,它是原子操作,当接受数据不及时到话,发送端将会一直阻塞,等到数据接收完全。
FIFO可以用shell命令mkfifo先创建一个,或者用C函数mkfifo()来实现一个,FIFO一旦创建完成,你就可以以操作文件到方式来操作它了,大概流程是:
打开FIFO==>读写操作==>关闭FIFO。
因为linux下到设备都是以文件形式存在的,所以很容易理解上述过程。
消息队列是在linux内核中建立消息链表来提供给进程间的通信。下面介绍下消息队列的基本操作。消息队列用来存放传送消息到结构在linux/msg.h里面定义:
上面的mtype是消息的类型,接受消息的mtype必须和发送端的mtype一样,当你写代码要发送消息的时候,得参照这个定义个结构体,long mtype是不能变的,下面的mtext[1]可以变成你想要到数字,用来存放消息。
消息队列还有一个由内核维护到结构struct msqid_ds,具体可以阅读头文件里到代码。当你要创建一个消息队列到时候,先得获得一个key,这个key通过ftok获得,不同进程之间利用这个key来区分队列,下面就简单介绍下具体操作:
ftok(pathname,project)生成一个key,不同进程之间用ftok函数的里面参数一样时,key是一样的,利用这个通信不同进程可以认识队列。
msgget(key,msgflag)创建一个队列或者找到相等的key的队列,flag主要是IPC_CREAT和IPC_EXCL,之用IPC_CREAT的时候,如果系统已经有key相等到队列,则返回那个key的队列,EXCL参数和CREAT一起用的时候,如果系统有那个key到队列,则返回一个失败值。
msgsnd(msgid,*msgp,size,flag) 该函数用来发送消息,msgid是创建队列时返回到标示,msgp就是你定义的存放消息的结构体,size是消息长度,它不包括mtype长度。举例如下:
上面代码里面msg_rflags=IPC_NOWAIT | MSG_NOERROR,msgrcv的第一个10代表接受信息大小,第二个时则是mtype,上面已经说过,只接受队列id里面到mtype相符的消息。msgctl则是对消息队列到内核管理的数据结构进行操作,具体可以man msgctl.
信号量可以理解成系统资源计数器,主要用来实现对临界资源到控制,如P,V操作。
基本函数如下:semget(key,int nsem,flag); 该函数创建信号量集合,nsem代表信号量个数。
semop(semid,*sops,nsops)对信号量进行操作,
上述结构体是semop的sops参数,sem_num是要处理到信号量编号,sem_op有三种形式,+1,-1,0,+1把信号量加上一个值,该值是semop到第三个参数nsops,-1是减值,0将该进程设置成睡眠状态,直到信号量值为0.
简单例子struct sembuf sops={0,+1,IPC_WAIT};semop(semid,&sops,1)
semctl是对信号量进行操作。信号量还有一个union semun,它用在semctl函数里面,基本上跟消息队列一样。
共享内存是最直接的IPC方式,多个进程按照一定到方式对这段内存进行操作,就像操作自己申请的内存一样。
shmget(key,size,flags),申请一个共享内存,返回共享内存表示符,shmid
*shmget(shmid,*shmaddr,shmflg)进程获得该内存,如果shmaddr为空,则系统会自动查找未映射到区域,该函数返回内存地址
shmdt(*shmaddr)删除共享内存,它不是真正删除共享内存,只是给内核一个标示,当没有进程用到该共享内存时候,内核才会把它删掉。
shmctl(shmid,cmd,shmid_ds),大致跟消息队列函数一样,参考man手册
通过上面,可以看到消息队列,信号量,共享内存用到到函数格式都差不多,如*get(),*ctl之类,值得注意到是,无论你是创建消息队列,信号量集合还是共享内存,都会用到key,这个key在前面讲过到ftok函数生成。
signal用来异步控制进程的,可以用kill -l列出系统到信号,当然大部分信号到默认操作是空操作或者终止进程,你可以用signal()函数来绑定信号和你要实现的功能,如
singal(sig_num,handler),sig_num是你到信号值,如SIGSTOP,handler是函数指针,就是说当sig_num发生时候,执行handler指向的函数。
如先定义handler(sig_num){.....},然后signal(SIGSTOP,handler);这样,当发生该信号时候,就执行handler函数。
可以通过kill(pid,sig)来向pid进程发送sig信号,当pid为0时,向所有进程发送sig信号。
也可以raise(sig)想当前进程发送信号。
具体的函数参数介绍和用法可参考man 手册。