进程间通信和同步

进程间通信和同步

半双工管道

原型:int pipe(int filedes[2]);

实质上是创建两个文件描述符,filedes[0]用于读,filedes[1]用于写。

当写入数据的数目小于PIPE_BUF时,写入是原子的,当大于PIPE_BUF时,可能不是原子的。

如果管道是空的,那么read会被阻塞,如果管道是满的,那么write会被阻塞。


命名管道

原型:int mkfifo(const char *pathname,mode_t mode);      //可用shell命令mkfifo创建

FIFO中,必须使用一个open函数来显式建立联接到管道的通道。一般来说FIFO总是处于阻塞的状态,如果FIFO打开时设置了读权限,则读进程将一直阻塞到其他进程打开该FIIFO并且向管道中写入数据,如果一个进程打开一个管道写入数据,当没有进程从管道读取数据时,写管道操作也是阻塞的。如果不希望进行命名管道操作的时候发生阻塞,可以调用open()调用中的O_NOBLOCK标志,以关闭默认的阻塞动作


消息队列

消息缓冲区结构msgbuf

struct msgbuf{

long mtype;

char mtext[1];

}

mtext可变长,缓冲区最大为#define MSGMAX 8192包括mtype 4字节。


内部的结构:


struct msqid_ds{


struct ipc_perm msg_perm;


time_t msg_stime; //发送到队列的最后一个消息的时间戳


time_t msg_rtime; //从队列中获取的最后一个消息的时间戳


time_t msg_ctime; //对队列进行最后一次变动的时间戳


unsigned long __msg_cbytes; //在队列上所驻留的字节总数


msgqnum_t msg_qnum; //当前处于队列中的消息数目


msglen_t msg_qbytes; //队列中能容忍的字节的最大数目


pid_t msg_lspid; //发送最后一个消息进程的PID


pid_t msg_lrpif; //接受最后一个消息进程的PID


};


struct ipc_perm{


key_t key; //函数msgget()使用的键值


uid_t uid; //用户的UID


gid_t gid; //用户的GID


uid_t cuid; //建立者的UID


git_t cgid; //建立者的GID


unsigned short mode; //权限


unsigned short seq; //序列号


};


键值构造函数ftok():

原型:key_t ftok(const char *pathname,int proj_id);

pathname必须是已存在的目录,proj_id则是一个8位的值,通常用a,b等表示。


获得消息msgget()函数:

原型:int msgget(key_t key,int msgflg);

第一个参数是键值,可以用ftok()函数生成,msgflag可指定权限,也可以指定操作IPC_CREATE,IPC_EXCL。IPC_EXCL本身没什么作用,但和IPC_CREATE一起用时可在已存在消息队列时返回一个错误。

成功返回标识符,错误返回-1


发送消息函数msgsnd()

原型:int msgsnd(int msqid,conset void *msgp,size_t msgsz,int msgflg);

msgfls可以为0也可以为IPC_NOWAIT,如果消息队列已满,则消息不会写入。如果没有指定IPC_NOWAIT,那么会阻塞。


接受消息msgrcv()

原型:ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg);

msgtype指定获取消息的类型如果传0,则获取最老的消息,忽略类型。msgsz表示消息缓冲区结构的大小,不包括mtype的长度。

如果msgflg为IPC_NOWAIT,则在没有消息时返回ENOMSG,否则阻塞。


消息控制msgctl()函数

原型:int msgctl(int msqid,int cmd,struct msgqid_ds *buf);

cmd如下

IPC_STAT

获得队列的msqid_ds结构,并把他存放到buf变量所指的地址中

IPC_SET

设置队列的msqid_ds结构的ipc_perm成员值,它从buf中取得该值

IPC_RMD

从内核删除该队列



信号量:

信号量数据结构:

union semun{

int val; //整形变量

struct semid_ds *buf; //semid_ds结构指针

unsigned short *array; //数组类型

struct seminfo *__buf; //信号量内部结构

};


新建信号量函数semget()

原型:int semget(key_t,int nsems,int semflg);

用于创建一个新的信号量集合,或者访问现有的集合。key是ftok产生的键值,nsems可以指定新的集合中应该创建的信号量的数目。第三个参数semflg是打开信号量的方式。

semflg指定权限,也可以加上IPC_CREATE、IPC_EXCL


信号量操作函数semop()

原型:int semop(int semid,struct sembuf *sops,unsigned nsops);

第二个参数是个指针,指向将要在信号量集合上执行操作的一个数组,而第三个参数则是该数组中操作的个数。

struct sembuf{

ushort sem_num; //信号量的编号

short sem_op; //信号量的操作

short sem_flg; //信号量的操作标志

}


sem_op如果为正,则从信号量加上一个值,为负减一个,为0将进程设置为睡眠状态, 直到信号量的值为0为止。


控制信号量参数semctl()

原型:int semctl(int semid,int semnum,int cmd,...);

semid是调用semget返回的值。semnum是要执行操作的信号量的编号,对于第一个信号量,他的索引值是0。cmd参数代表将要在该集合执行的命令

cmd取值:

IPC_STAT

获取某个集合的semid_ds结构,将它存储到semun联合体的buf参数指定的地址中

IPC_SET

设置某个集合的semid_ds结构的ipc_perm成员的值,该命令所取得值从semun联合体的buf参数中取到

IPC_RMID

从内核中删除该集合

GETALL

获取集合值中所有信号量的值,整数值存放在无符号短整数的一个数组中该数组由联合体的array成员所指定

GETNCNT

返回当前正在等待资源的进程的数目

GETPID

返回最后一次执行semop调用的进程的PID

GETVAL

返回集合中某个信号量的值

GETZCNT

返回正在等待资源利用率达百分之百的进程的数目

SETALL

设置集合中所有信号量的值为联合体array成员所包含的对应值

SETVAL

把集合中单个信号量的值设置为联合体的val成员的值



共享内存:

创建共享内存函数shmget()

原型:int shmget(key_t key,size_t size,int shmflg);


获得共享内存地址函数shmat()

原型:void * shmat(int shmid,const void *shmaddr,int shmflg);

shmaddr若为0,则内核试着查找一个为映射的区域。

SHM_RND可以与标志参数进行OR操作,可以让传送的地址页对齐

SHM_RDONLY,标志共享内存段为只读。


删除共享内存shmdt()

原型:int shmdt(const void *shmaddr);

切断进程与该内存段的联系,非真正删除。


控制函数shmctl()

原型:int shmctl(int shmid,int cmd,struct shmid_ds *buf);

与msgctl完全类似。




信号:

信号截取函数signal()

原型:sighandler_t signal(int signum,sighandler_t handler);

handler函数原型:void sighandler(int signo); signo将传入信号值


向进程发送信号kill()和raise()

原型:int kill(pid_t pid,int sig);

        int raise(int sig);

kill函数当pid为0时群发所有进程。raise是在当前进程自举一个信号。


本文出自http://qianyang.blog.51cto.com/,转载请务必注明出处

你可能感兴趣的:(c,linux,进程间通讯)