一进程通信概述
1为什么进程间需要通信
(1)数据传输;--一个进程需要它的数据发送给另一个进程。
(2)资源共享;----多个进程之间共享同样的资源
(3)通知事件;----一个进程需要向另一个或一组发送信息,通知它们发生了某种事件。
(4)进程控制------有些进程希望完全控制另一个进程的执行
2
linux使用的进程间通信方式包括:
管道和有名管道FIFO
信号(signal)
消息队列
共享内存
信号量
3
linux使用存在每个进程task_struct结构中的信息实现信号机制,它支持的信号数受限于处理器的字长。
处理器的字长-----CPU的字长通常是指CPU内部数据总线宽度或位数。
4
linux支持最早在UNIX system V中出现三种进程间通信,它们是信息队列、信息量和共享存储器。
二管道通信
1
管道是单向的、先进先出的;写进程在管道尾部写入数据,读进程从管道的头部读出数据。
2
管道分无名管道和有名管道。
前者用于父子进程间通信;后者运行于同一系统中的任意两个进程间的通信。
3
无名管道
由pipe()函数创建
int pipe(int filedis[2])
filedis[0]用于读管道--头部;filedis[1]用于写管道--尾部。
4
管道关闭close
5
管道通信程序:
....
6
注意事项:必须在系统调用fork前调用pipe,否则子进程将不会继承文件描述符。
7
实例演练:pipe_rw.c
....
8
pid=0,则下面对应的是在进程中完成
pid>0,则在父进程中完成。
9
命名管道(FIFO)
10
创建
int mkfifo(const char*pathname,mode_t mode)
11
O_NONBLOCK
没使用。。,访问要求无法满足,进程将阻塞。
使用。。。,访问要求无法满足,进程不阻塞,立刻出错返回。errno是ENXIO。
三信号通信
1忽略此信号,但SIGKILL和SIGSTOP不能被忽略
2
执行用户希望的动作
3
执行系统默认的动作
对于大多数信号的系统默认动作是终止该进程
4
kill:能给自身发生信号,也可以向其他进程发送信号。
raise:向进程自身发生信号。
ps aux //查看当前进程进程号
发送
kill -s SIGQUIT 3687
给哪个PID发,用S指定
5
alarm函数可以设置一个时间值(闹钟时间),当所设置的时间到了时,产生SIGALRM信号
unsigned int alarm(unsigned int seconds)
6
paue函数:使调用进程挂起直至捕捉到一个信号。
7
信号处理
signal:是一个函数指针,有返回类型返回参数
SIG_IGN:忽略此信号
SIG_DFL:按系统默认方式处理
信号处理函数名:使用该函数处理
8
程序:mysignal.c
四共享内存
1
共享内存实现分为两步:
(1)创建共享内存,使用shmget函数
(2)映射共享内存,将这段创建的共享内存映射到具体的进程空去,使用shmat。
2
int shmget(key_t key,int size,int shmflg)
key标志共享内存的键值:0/IPC_PRIVATE.
当key取后者时,函数shmget将创建一块新的内存。如果key取0,而第三个参数又设置IPC_PRIVATE这个标志,则同样创建一块新的共享内存。
3
int shmat(int shmid,char*shmaddr,int flag)
shmid:函数返回共享存储标志符
shmaddr:赋值0,系统帮你制定个地址
flag:决定以什么方式来确定映射的地址,通常为0
返回值:
如果成功返回共享内存映射到进程中的地址,如果失败,则返回-1
4
当一个进程不再需要共享内存时,需要把它从进程地址空间中脱离。
int shmdt(char*shmaddr)
五消息队列
1
消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式。
2
消息队列和管道有点相似,你把数据读走后,它不在存在。
管道则只能传送无格式的字节流。
3
两种:POSIX消息队列和系统V消息队列
POSIX可移植的操作系统接口
4
消息队列随内核持续。
int msgget(key_t key,int msgflg)
5
msgflg:标志位可以取如下:
IPC_CREAT:创建新的消息队列
IPC_EXCL:与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误
IPC_NOWAIT:读写消息队列要无法得到满足时,不阻塞。
6
key_t ftok(char*pathname,char proj)//文件名,项目名
返回文件名对应的键值
int msgget(key_t key,int msgflg)
返回与键值key相对应的消息队列描述字。
两种情况下,将创建一个新的消息队列
(1)msgflg:包含IPC_CREAT标志位
(2)key参数为IPC_PRIVATE。
7
发送消息的函数
int msgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg)
参数描述
msqid:已打开的消息队列id
msgp:存放消息的结构
msgsz:消息数据长度
msgflg:发送标志,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待。
8
消息格式
struct msgbuf
{
long mtype;//消息类型>0,类型只能有一个,收发都用通一个类型
char data[255];//数据
}
9
接收消息
int msgrcv(int msgid,struct msgbuf*msgp,int msgsz,long msgtyp,int msgflg)
从msqid代表的消息队列中读取一个msgtyp类型的消息,并把消息存储在msgp指向的msgbuf结构中。在成功地读取了一个消息以后,队列中的这条消息被删除。
消息取出后放在qbuf所指向的位置。
10
%x
%p指针所指的地址
%h
11
一个类型里有多个消息
六信号量
1
信号量:主要用途是:进程间的控制,比如说控制互斥同步,保护临界资源,控制进程按一定的先后顺序执行
2
除用于访问控制外,还可用于进程同步。
3
二值信号灯:只能取0或1,类似于互斥锁。
但两者不同:信号灯强调共享资源,只有共享资源可用,其他进程同样可修改信号灯的值。
计数信号灯:信号灯的值可以取任意非负值。
4
创建/打开
int semget(key_t key,int nsems,int semflg)
key :键值,由ftok获得
nsems:指定打开或者新创建的信号灯集中将包含信号灯的数目
semflg:标志,同信息队列。
5
操作
int semop(int semid,struct sembuf*sops,unsigned nsops)
对信号量进行控制
semid:信号量集的ID
sops:是一个操作数组,表明进行什么操作
nsops:sops所指向的数组的元素个数
6
IPC_NOWAIT:对信号的操作不能满足时,semop()不会阻塞,并立即返回
IPC_UNDO:程序结束时释放信号量,避免结束时未将锁定的资源解锁,造成该资源永远锁定。