学习笔记,小白可以相互学习,大佬看到能告诉咱理解不对的地方就好了。
Linux下进程通信概述:
传统的进程间通信方式:无名管道(pipe),有名管道(fifo),信号(signal)
System V IPC对象:共享内存,消息队列,信号灯
BSD:套接字(socket)
1.无名管道
特点:只能用于具有亲缘关系的进程之间通信。
半双工的通信模式,具有固定的读端和写端。
可以看成一种特殊的文件,对他的读写可以使用文件IO(write,read,不可用lseek)。
1.1无名管道的创建与关闭
管道是基于文件描述符的通信方式。当一个管道建立时,他会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,fd[1]固定用于写管道。构成了一个半双工的通道。
头文件 | #include<unistd.h> |
原型 | int pipe(int fd[2]) |
参数 | fd:包含2个元素的整型数组 |
返回值 | 成功:0 出错:-1 |
管道读写注意点:
只有当管道的写端关闭,读端才会返回0,否则读端阻塞。
当管道中无数据时,读操作会操作会阻塞。
如果读进程不读走管道缓冲区中的数据,那么写操作将会一直阻塞。
只有在管道读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIGPIPE信号。导致进程死亡。
当读端关闭,写端还在继续写入数据,则会管道破裂,进程直接结束。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
int fd[2];
if( 0 > pipe(fd))
{
perror("pipe");
exit(-1);
}
printf("fd: %d %d\n",fd[0],fd[1]);
close(fd[0]);
close(fd[1]);
return 0;
}
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int fd[2];
if( 0 > pipe(fd))
{
perror("pipe");
exit(-1);
}
pid_t pid;
char buf[100];
if( 0 > (pid=fork()))
{
perror("fork");
exit(-1);
}
else if(pid == 0)//子进程,写
{
close(fd[0]);//关闭读端
while(1)
{
fgets(buf,sizeof(buf),stdin);
write(fd[1],buf,sizeof(buf));
if(strncmp(buf,"quit",4) == 0)//比较buf和“qui”的前4个字符
{
break;
}
}
}
else//父进程,读
{
close(fd[1]);//关闭写端
int ret;
while(1)
{
ret = read(fd[0],buf,sizeof(buf));
if(ret < 0)
{
perror("read");
break;
}
else if( 0 == ret)
{
printf("write colse\nd");//只有当写端关闭,读端才会返回0,否则读端阻塞
break;
}
fputs(buf,stdout);
}
close(fd[0]);
}
return 0;
}
/***************实现copy功能*************************************/
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/types.h>
int main(int argc,char *argv[])
{
if( argc < 3)
{
printf("把filename1中的内容复制到filename2中去\n");
fprintf(stdout,"usage:%s filename1 filename2\n",argv[0]);
exit(-1);
}
int fd[2];//建立管道
if( 0 > pipe(fd))
{
perror("pipe");
exit(-1);
}
int ret;
char buf[100];
pid_t pid;
if(0 > (pid = fork()))//建立进程
{
perror("fork");
exit(-1);
}
/***********************************************************************/
else if(pid == 0)//***子进程中,文件的读操作,管道的写操作**************
{
close(fd[0]);//关闭读管道
int fd1 = open(argv[1],O_RDONLY);//filemame1以只读方式打开
if(0 > fd1)//判断文件是否打开成功
{
perror("open filename1");
exit(-1);
}
while(1)
{
if(0 > (ret = read(fd1,buf,sizeof(buf))))//读文件,写入buf
{
perror("read");
exit(-1);
}
else if(ret == 0)
{
printf("read file end\n");
close(fd1);//关闭文件1
break;
}
if(0 > write(fd[1],buf,ret))//把buf写入管道
{
perror("write");
exit(-1);
}
}
close(fd[1]);//关闭写管道
}
/***********************************************************************/
else//*******父进程中,管道读操作,文件写操作***************************
{
close(fd[1]);//关闭写管道
int fd2 = open(argv[2],O_WRONLY | O_CREAT | O_TRUNC,0666);//打开文件2
if(0 > fd2)//判断是否打开成功
{
perror("open filename2");
exit(-1);
}
while(1)
{
ret = read(fd[0],buf,sizeof(buf));//读管道,写入buf
if( 0 > ret )
{
perror("read fd");
exit(-1);
}
else if( 0 == ret)
{
printf("管道内容读取完毕\n");
close(fd[0]);//关闭读管道
break;
}
if(0 > write(fd2,buf,ret))//把管道内容(已结传给buf了),写入文件2
{
perror("write file2");
exit(-1);
}
}
close(fd2);//;关闭文件2
}
return 0;
}
有名管道可以使互不相关的两个进程互相通信。进程通过文件io来操作有名管道,文件内容存在于内核之中。不支持lseek()操作。
头文件 | #include<unistd.h> #include<fcntl.h> #include<ss/types.h> |
原型 | int mkfifo(const char*filename,mode_t mode); |
参数 | filename:要创建的管道名字 mode:管道的权限,用8进制表示 |
返回值 | 成功:0 出错:-1 |
/****建立fifo****************************************************/
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
int main()
{
if( 0 > mkfifo("myfifo",0777))
{
perror("mkfifo");
exit(-1);
}
printf("mkfifo success\n");
return 0;
}
//2个进程实现一个读一个写
/***********************fifo_read*******************************************/#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: %s <fifo> \n", argv[0]);
exit(-1);
}
int fd;
if (0 > (fd = open(argv[1], O_RDONLY))) {
perror("open");
exit(-1);
}
char buf[100];
int ret;
while (1) {
ret = read(fd, buf, sizeof(buf));
if (ret < 0) {
perror("read");
break;
}else if (ret == 0) {
printf("write close\n");
break;
}
fputs(buf, stdout);
}
close(fd);
return 0;
}
/***********************fifo_write*******************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
void handler(int sigo)
{
printf("I got a SIGPIPE\n");
}
int main()
{
int fd;
if (0 > (fd = open("myfifo", O_WRONLY))) {
perror("open");
exit(-1);
}
signal(SIGPIPE, handler);
char buf[100];
int ret;
while (1) {
fgets(buf, sizeof(buf), stdin);
if (0> (ret = write(fd, buf, sizeof(buf)))) {
perror("write");
break;
}
if (strncmp(buf, "quit", 4) == 0)
break;
}
close(fd);
return 0;
}
//************************************************************************************************
//*******************************实现copy功能*************************************************
//************************************************************************************************
/*******建立fifo************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
int main()
{
if(0 > (mkfifo("myfifo",0666)))
{
perror("mkfifo");
exit(-1);
}
printf("mkdido success\n");
return 0;
}
/*********read-fifo******************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
int main(int argc,char *argv[])
{
if(argc < 2)
{
fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
exit(-1);
}
int fin,fout;
char buf[100] = {0};
if( 0 > (fin = open(argv[1],O_RDONLY))) //源文件
{
perror("open_fin");
exit(-1);
}
if(0 > (fout = open("myfifo",O_WRONLY)))
{
perror("open_fout");
exit(-1);
}
int ret;
while(1)
{
if(0 > (ret = read(fin,buf,sizeof(buf))))
{
perror("read");
break;
}
else if(ret == 0)
{
printf("write end\n");
break;
}
write(1, buf, ret); //从源文件读到的内容写入终端
if(0 > write(fout,buf,ret))
{
perror("write");
break;
}
}
close(fin);
close(fout);
return 0;
}
/***********write-fifo*****************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
if(3 > argc)
{
fprintf(stderr,"Usage: %s <fifo><destfile>\n",argv[0]);
exit(-1);
}
int fin, fout;
if(0 > (fin = (open(argv[1],O_RDONLY)))) //管道文件
{
perror("open_fin");
exit(-1);
}
if(0 > (fout = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666)))//目标文件
{
perror("open_fout");
exit(-1);
}
int ret;
char buf[100] = {0};
while(1)
{
if(0 > (ret = read(fin,buf,sizeof(buf))))
{
perror("read");
break;
}
else if(ret == 0)
{
printf("write close\n");
break;
}
if(0 > write(fout,buf,ret))
{
perror("write");
break;
}
}
close(fin);
close(fout);
return 0;
}
3.信号通信
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。
信号的生存周期:1.信号产生---》2.信号注册---》3.信号注销---》4.信号处理
1是在内核进程中,23是在用户进程中
用户进程对信号的处理方式:
忽略信号:对信号不做任何处理,但是有两个信号不能忽略,即SIGKILL 和 SIGSTOP
捕捉信号:定义信号处理函数,当信号发生时,执行相应的处理函数
执行缺省操作:Linux对每种信号都规定了默认操作
信号名 含义 默认操作
SIGHUP | 终止 | |
SIGINT | 相当于ctrl c | 终止 |
SIGQUIT | 相当于ctrl \ | 终止 |
SIGILL | 终止 | |
SIGFPE | 终止 | |
SIGKILL | 立即结束程序的运行,不能被 终止,阻塞处理和忽略 | 终止 |
SIGALRM | 当一个定时器到时的时候发出 | 终止 |
SIGSTOP | 暂停进程 | |
SIGTSTP | 暂停进程 | |
SIGCHLD | 子进程改变状态时,父进程会 收到这个信号 | 忽略 |
SIGABORT | 终止 |
3.1kill()和raise()
kill -l命令查看系统支持的信号列表
raise函数进程只能自己发送信号
头文件 | #include<signal.h> #include<sys/types.h> |
原型 | int kill(pid_t pie,int sig); |
参数 | pid:正数:要接受信号的进程号 0:信号被发送到所有和pid进程在同一个进 程组的进程 -1:信号发送给所有的进程表中的进程 (除了进程号最大的进程外(即init)) |
返回值 | 成功;0 出错:-1 |
头文件 | #include<signal.h> #include<sys/types.h> |
原型 | int raise(int sig);(等同于kill(getpid,sig)) |
参数 | sig:信号 |
返回值 | 成功:0 出错:-1 |
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
if (0 > (pid = fork())) {
perror("fork");
exit(-1);
}else if (pid == 0) {
printf("child!\n");
sleep(2);
#if 0
if (0 != raise(SIGKILL)) {
printf("raise error\n");
exit(-1);
}
#else
if (0 > kill(getpid(), SIGKILL)) {
perror("kill");
exit(-1);
}
#endif
printf("child!\n");
exit(0);
}
printf("parent!\n");
/*
//if (0 > kill(pid, SIGKILL)) {
if (0 > kill(pid, 9)) {
perror("kill");
exit(-1);
}
*/
int status;
if (0 > wait(&status)) {
perror("wait");
exit(-1);
}
if (WIFEXITED(status)) {
printf("child exit normally!\n");
}else
printf("child exit abnormally!\n");
return 0;
}
3.2alarm()和psuse()
alarm()也称为闹钟函数,他可以在进程中设置一个定时器。当定时器指定的时间到时,内核就向进程发送SIGALARM信号
多个alarm()后一个会把前一个覆盖掉
psuse()函数使用于将调用的进程挂起直到收到信号为止。(挂起一个进程,直到收到一个信号为止)
头文件 | #include<unistd.h> |
原型 | unsigned int alarm(unsiged int seconds) |
参数 | seconds:指定秒数 |
返回值 | 成功:如果调用此alarm()前,进程中已经设置 了闹钟时间,则返回上一个闹钟时间的剩余时间 ,否则返回0 出错:-1 |
头文件 | #include<unistd.h> |
原型 | int pause(void) |
返回值 | -1,并且把error值设置为EINTR |
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
int main()
{
alarm(5);
while (1) {
alarm(2);
printf("hello world\n");
sleep(1);
}
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
int main()
{
alarm(5);
printf("hello world!\n");
sleep(2);
pause();
printf("hello world\n");
return 0;
}
4.信号的处理
信号处理的主要方法有两种:1使用简单的signal()函数,2使用信号集函数族sigaction()
使用signal()函数处理时,需指定要处理的信号和处理函数,使用简单,便于理解。
头文件 | #include<signal.h> |
原型 | viod *(signal(int signum,void(*hander)(int)))(int); |
参数 | signum:指定信号 hander:SIG_IGN忽略该信号 SIG_DFL采用系统默认方式处理信号 自定义的信号处理函数指针 |
返回值 | 成功:设置之前的信号处理方式 出错:-1 |
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <signal.h>
int main()
{
signal(SIGINT, SIG_IGN); //忽略ctrl+c
signal(SIGQUIT, SIG_IGN); //忽略ctrl+\
while (1) {
sleep(1);
printf("hello world\n");
}
return 0;
}
void handler(int sigo)
{
if (sigo == SIGCHLD)
{
wait(NULL);
printf("Got a child body\n");
}
}
int main()
{
signal(SIGCHLD, handler);
pid_t pid;
if (0 > (pid = fork())) {
perror("fork");
exit(-1);
}else if (pid == 0) {
sleep(1);
printf("child!\n");
exit(-1);
}else {
printf("parent\n");
sleep(3);
}
return 0;
}
4.共享内存
共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据形式的拷贝。
为了在多个进程间交换信息,内核专门流出了一块内存区,可以由需要访问的进程将其映射到自己私有的地址空间。进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高了效率。
共享内存查看命令:ipcs -m,删除命令:ipcrm -m shmid
共享内存的使用包括以下步骤:
1.创建/打开共享内存
2.映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
3.撤销共享内存映射
4.删除共享内存对象
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> |
原型 | int shmget(key_t key,int size,int shmflg); |
参数 | key:IPC_PRIVATE或fork的返回值 size:共享内存区大小 shmflg::同open函数权限位,也可用8进制表示 |
返回值 | 成功:共享内存段标识符 出错:-1 |
(说明:ftok()打开文件对应的路径生成唯一的一个key值,原型key_t ftok(const char*name,int projoid),后一个参数是子序号0-255)
(shmflg,用IPC_CREAT创建,例如IPC_CREAT | 0777)
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> |
原型 | void *shmat(int shmid,const void*shmaddr,int shmflg); |
参数 | shmid:要映射的共享内存区标识符 shmadr:将共享内存映射到指定地址(NULL 则由系统自动完成映射) shmflg:默认0,共享内存可读写 SHM_RDONLY共享内存只读 |
返回值 | 成功:映射后的地址 出错:-1 |
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> |
原型 | int shmid(const void *shmaddr) |
参数 | shmaddr:共享内存映射后的地址 |
返回值 | 成功:0 出错:-1 |
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> |
原型 | int shmctl(int shmid,int cmd,struct shmid_ds *buf) |
参数 | shmid:要操作的共享内存标识符 cmd:IPC_STAT获取对象属性 IPC_SET设置对象属性 IPC_RMID删除对象,第三个参数设NULL |
返回值 | 成功:0 出错:-1 |
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
//创建一个共享内存,在共享内存中存放数据
int main()
{
system("ipcs -m");//相当于在终端直接输入命令ipcs -m,调用系统命令
key_t key = ftok(".",'a');//得到key值
if((key_t)-1 == key)//强转-1的类型为key_t
{
perror("ftok");
exit(-1);
}
//创建或者获取共享内存段ID
int shmid = shmget(key,100,IPC_CREAT|0666);//使用IPC_CREAT创建,并且设置权限
if(-1 == shmid)
{
perror("shmget");
exit(-1);
}
//把共享内存映射到用户空间
void *ptr = shmat(shmid,NULL,0);
if((void *)-1 == ptr)
{
perror("shmat");
exit(-1);
}
//往映射的空间存放数据
strcpy((char *)ptr,"hello world!");
system("ipcs -m");
return 0;
}
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
//创建一个共享内存,在共享内存中获取存放数据
int main()
{
system("ipcs -m");//相当于在终端直接输入命令ipcs -m,调用系统命令
key_t key = ftok(".",'a');//得到key值
if((key_t)-1 == key)//强转-1的类型为key_t
{
perror("ftok");
exit(-1);
}
//创建或者获取共享内存段ID
int shmid = shmget(key,100,IPC_CREAT|0666);//使用IPC_CREAT创建,并且设置权限
if(-1 == shmid)
{
perror("shmget");
exit(-1);
}
//把共享内存映射到用户空间
void *ptr = shmat(shmid,NULL,0);
if((void *)-1 == ptr)
{
perror("shmat");
exit(-1);
}
//从映射的空间取出数据
printf("ptr:%s\n",(char *)ptr);
system("ipcs -m");
//解除映射
if( 0 > shmdt(ptr))
{
perror("shmdt");
exit(-1);
}
//删除共享内存段
if( 0 > shmctl(shmid,IPC_RMID,NULL))
{
perror("shmctl");
exit(-1);
}
system("ipcs -m");
return 0;
}
5.消息队列
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> |
原型 | int msgget(key_t key,int flag) |
参数 | key:消息队列关联的key值 flag:消息队列的访问权限 |
返回值 | 成功:消息队列ID 出错:-1 |
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> |
原型 | int msgsnd(int msqid,const coid* msgp,size_t size,int flag) |
参数 | msqid:消息队列ID msgp:指向消息的指针,常用消息结构体msgbu struct msgbuf{ long mtype://消息类型 char mtex[N];//消息正文 } size:发送的消息正文的字节数 flag:IPC_NOWAIT消息没有发送完成函数也会 立即返回 0:直到发送完成函数才会返回 |
返回值 | 成功:0 出错:-1 |
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> |
原型 | int msgrcv(int msgid,void *msgp,size_t size,long msgtype,int flag) |
参数 | migid:x消息队列ID msgp:接收消息的缓存区(就是结构体的地址) size:要接收的正文消息字节数 msgtype:0:接收消息队列中第一个消息( 一个一个接收) 大于0:接收消息队列中第一个类型为 mstype的消息 小于0:接收消息队列中类型值不小于msgtype 的绝对值且类型又最小的消息 flag:0,若无纤细函数会一直阻塞 IPC_NOWAIT 若没有消息,进程会立即 返回ENOMSG |
返回值 | 成功:接收到消息的长度 出错;-1 |
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> |
原型 | int msgctl(int msgid,int cmd,struct msgid_ds *buf) |
参数 | msgid:消息队列的ID cmd:IPC_STAT读取消息队列的属性,并将 其保存在buf指向的缓存区中 IPC_SET:设置消息队列的属性,这个值 自取buf参数 IPC_RMID从系统中删除消息队列( 此时第三个参数设为NULL) |
返回值 | 成功:0 出错:-1 |
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
//创建一个消息队列,添加消息到消息队列
struct msgbuf{
long mtype;
char mtext[100];
};
int main()
{
system("ipcs -q");
key_t key = ftok(".",'a');
if((key_t)-1 == key)
{
perror("ftok");
exit(-1);
}
//创建消息队列
int msgid = msgget(key,IPC_CREAT | 0666);
if(msgid < 0)
{
perror("msgget");
exit(-1);
}
system("ipcs -q");
//添加消息到消息队列中
struct msgbuf msg;//定义一个消息结构体变量
msg.mtype = 100;
strcpy(msg.mtext,"hello world");
if( 0 > msgsnd(msgid,&msg,sizeof(msg)-sizeof(long),0))
{
perror("msgsnd");
exit(-1);
}
system("ipcs -q");
return 0;
}
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
//创建一个消息队列,获取消息到消息队列
struct msgbuf{
long mtype;
char mtext[100];
};
int main()
{
system("ipcs -q");
key_t key = ftok(".",'a');
if((key_t)-1 == key)
{
perror("ftok");
exit(-1);
}
//创建或获取消息队列
int msgid = msgget(key,IPC_CREAT | 0666);
if(msgid < 0)
{
perror("msgget");
exit(-1);
}
system("ipcs -q");
//接收消息到消息队列中
struct msgbuf msg;//定义一个消息结构体变量
msg.mtype = 100;
strcpy(msg.mtext,"hello world");
int ret;
if( 0 > (ret = msgrcv(msgid,&msg,sizeof(msg)-sizeof(long),100,0)))
{
perror("msgrcv");
exit(-1);
}
printf("text:%d,%s\n",ret,msg.mtext);
system("ipcs -q");
//删除消息队列
if(0>msgctl(msgid,IPC_RMID,NULL))
{
perror("msgctl");
exit(-1);
}
system("ipcs -q");
return 0;
}
6.信号灯(信号量)
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> |
原型 | int semget(key_t key,int nsems,int semflg); |
参数 | key:信号灯集关联的key值 nsems:信号灯集中包含的信号灯数量 semflg:信号灯的访问权限,通常为 IPC_CREAT|0666 |
返回值 | 成功:信号灯集ID 出错:-1 |
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> |
原型 | int semop(int semid,struct sembuf *opsptr,size_t nops); |
参数 | semid:信号灯集ID(从0开始) struct sembuf{ short sem_num;//要操作的信号灯编号 short sem_op;//0:等待,直到信号灯的值 变为0 //1:释放资源 ,V操作 //-1:分配资源,P操作 short sem_flg;//0,IPC_NOWAIT,SEM_UNDO } |
返回值 | 成功:0 出错:-1 |
头文件 | #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> |
原型 | int semctl(int semid,int semnum,int cmd.../*union semun arg*/); |
参数 | semid:信号灯集ID semnum:要修改的信号灯编号 cmd:GETVAL:获取信号灯的值 SETVAL;设置信号灯的值 //有前面这2个是,有第四个参数(共用体) IPC_RMID:从系统中删除信号灯集合 |
返回值 | 成功:0 出错:-1 |
/********************************************************************************************************/
/******************************代码在实验手册上改天抄下来****************************************/
6.进程间通讯方式比较