进程基础知识
首先关于进程需要知道的是:
- 进程间的通信(信息的交互)必须经过内核
- 进程通信是基于文件IO的思想,就像是驱动开发的时候对文件的操作一样,有打开、读写、关闭一类的操作(只不过个别函数不一样)
写操作只能是char型的 - 我们平时写代码时的main(),就是创建了一个主进程,在这个主进程中用fork()函数可以创建这个主进程的子进程,即这两个进程为父子进程
- Linux中查看进程
ps -axj //-a 选项表示显示所有用户的进程,而不仅仅是当前用户的进程。 //-x 选项表示显示没有终端控制的进程。这包括后台进程和守护进程。 //-j 选项用于以作业格式(包括pid等信息)显示进程信息。
- Linux中进程状态:
- S+为睡眠,T+为暂停,Z+为僵死进程
- 回收子进程用wait,暂停进程用raise,睡眠用sleep
- 父子进程关系:
-
fork()函数创建子进程,返回值类型为pid_t p;p<0创建失败;p>0说明当前运行为父进程;p=0为子进程
#include<stdio.h> #include<sys/types.h> #include<unistd.h> int main(){ pid_t p1; p1=fork(); if(p1<0) printf("p1 fork error!\r\n"); else { sleep(3); printf("%d\r\n",p1); } return 0; }
-
实现父进程创建一个子进程1,子进程1再创建子进程2;且父进程打印b,子进程1打印c,子进程2打印a
#include<stdio.h> #include<sys/types.h> #include<unistd.h> int main(){ pid_t p1,p2; if(p1=fork()) //只有父进程到这里的时候,才会执行(子进程返回值为0) putchar('b'); else //子进程1执行 { if(p2=fork()) //创建子进程2 putchar('c'); else //子进程2执行 { putchar('a'); } } return 0; }
-
实现父进程先运行,运行完后子进程再运行
#include<stdio.h> #include<sys/types.h> #include<stdlib.h> #include <unistd.h> int main(){ pid_t p1,p2; int process_inter=0; p1=fork(); if(p1==0) //子进程 { while (process_inter==0); //为0等待 for(int i=0;i<5;i++) { printf("this is child process i=%d\n",i); usleep(100); } } if(p1>0) //父进程 { for(int i=0;i<5;i++) { printf("this is parent process i=%d\n",i); usleep(100); } process_inter=1; } return 0; }
-
进程通信
我看到关于进程通信分类,其实按照不同的划分方式有很多种不一样的划分,但是这个不用纠结太深,具体的通信方法就那么几种。这里我主要分为管道通信、信号通信、IPC通信。
所有不同的通信方式,其实都是一样的,都是在内核中有一个对象,两个进程的通信必须通过这个对象,只不过这个对象有时是管道(管道通信),有时是信号(信号通信)或者内存(共享内存通信)等,不同对象的操作函数不一样罢了
管道通信
就是在内核中创建了一个对象,只不过这个对象是管道,进程a要给b发送数据,必须要先a——管道——b
无名管道
- 无名管道就是无文件节点,我理解的就是相当于没有文件实体,文件肯定有文件名等其他文件属性,但是无名管道就没有文件名这些。所以就不能通过文件名来操作无名管道
- 缺点:不能实现非父子进程(亲缘关系)之间的通信
- 代码实现:
-
pipe()函数创建无名管道,创建成功返回0,失败返回-1
参数:就是文件描述符。fd[1]是出队的文件描述符,fd[0]是入队(队列的左右两边)#include <unistd.h> #include <stdio.h> #include <stdlib.h> //1. pipe创建管道 int main(){ int fd[2]; int ret; ret=pipe(fd); if(ret<0) { printf("pipe creat failed!\n"); return -1; } else { printf("pipe creat success!\n"); printf("fd[0]=%d,fd[1]=%d\n",fd[0],fd[1]); } return 0; }
-
进程向无名管道写数据,再从管道中读数据
写要写从队列的出队描述符fd[1]开始写,读要从队列的入队描述符fd[0]开始读#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(){ int fd[2]; int ret; char writebuf[]="hello linux!"; char readbuf[50]={0}; char readbuf2[50]={0}; ret=pipe(fd); if(ret<0) { printf("pipe creat failed!\n"); return -1; } else { printf("pipe creat success!\n"); printf("fd[0]=%d,fd[1]=%d\n",fd[0],fd[1]); } ret=write(fd[1],writebuf,sizeof(writebuf)); if(ret<0) { printf("pipe write failed!\n"); return -1; } ret=read(fd[0],readbuf,50); if(ret<0) { printf("pipe read failed!\n"); return -1; } printf("pipe readbuf=%s\n",readbuf); //验证读阻塞 // ret=read(fd[0],readbuf2,50); // printf("pipe readbuf2=%s\n",readbuf2); close(fd[0]); close(fd[1]); return 0; }
-
利用无名管道实现子进程等待,父进程先运行后子进程运行
#include<stdio.h> #include<sys/types.h> #include<stdlib.h> #include <unistd.h> int main(){ pid_t p1; int fd[2]; int ret; char process_inter=0; //必须在创建进程前创建管道,这样两个进程才继承的同一个管道。如果先创建进程后创建管道,那么父子进程会分别创建自己一个管道 ret=pipe(fd); if(ret<0) { printf("pipe creat failed!\n"); return -1; } printf("pipe creat success!\n"); p1=fork(); if(p1==0) //子进程 { read(fd[0],&process_inter,1); //数组名就是指向首元素地址的指针,就不用加& while (process_inter==0); //为0等待 for(int i=0;i<5;i++) { printf("this is child process i=%d\n",i); usleep(100); } } if(p1>0) //父进程 { for(int i=0;i<5;i++) { printf("this is parent process i=%d\n",i); usleep(100); } process_inter=1; write(fd[1],&process_inter,1); } while (1); return 0; }
-
有名管道
-
有文件节点,属于Linux七种文件类型中的管道文件p,不占用磁盘空间。也就是创建的管道文件是有实体的,能在系统中找到
-
能实现非父子进程(亲缘关系)之间的通信
-
有名管道文件操作是典型的文件操作,有mkfifo,open、读写、关闭
-
代码实现:
-
mkfifo()函数创建有名管道文件,创建成功返回0,失败返回-1
参数:filename:文件路径和文件名,mode:文件权限,跟umask有关#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> //创建管道文件 int main() { int ret; /*int mkfifo(const char * filename,mode_ t mode);*/ ret=mkfifo("./myfifo",0777); //在当前目录下创建一个管道文件 if(ret<0) { printf("mkfifo failed!\n"); return -1; } printf("mkfifo success!\n"); return 0; }
-
实现两个非亲缘关系的进程之间的通信。要求进程1先运行完后,进程2运行
-
进程1代码:
#include "unistd.h" #include "stdio.h" #include "sys/types.h" // 提供mode_t类型 #include "stdlib.h" #include "fcntl.h" // 提供open()函数 #include "sys/stat.h" // 提供open()函数的符号 int main() { int ret,fd; char inter=0; ret=mkfifo("./myfifo",0777); if(ret<0) { printf("mkfifo failed!\n"); return -1; } printf("mkfifo success!\n"); fd=open("./myfifo",O_WRONLY); if(fd<0) { printf("open failed!\n"); return -1; } printf("open success!\n"); for(int i=0;i<5;i++) { printf("this is first process i=%d\n",i); usleep(200); } inter=1; sleep(5); write(fd,&inter,1); while (1); return 0; }
-
进程2代码:
#include "unistd.h" #include "stdio.h" #include "sys/types.h" #include "stdlib.h" #include <fcntl.h> #include <sys/stat.h> int main() { int fd; char inter; fd=open("./myfifo",O_RDONLY); if(fd<0) { printf("second_process open failed!\n"); return -1; } printf("first_process open success!\n"); read(fd,&inter,1); while(inter==0); for(int i=0;i<5;i++) { printf("this is second process i=%d\n",i); usleep(100); } while(1); return 0; }
-
-
信号通信
-
就是内核中用于两个进程通信的对象是信号,信号是存在于内核中的,不像管道那样需要单独去创建
- 查看Linux中64种信号的命令:
kill -l
常用的命令如:- 9 SIGKILL #杀死进程
- 2 SIGINT #键盘发送的终止信号(用pause时)
- 10 SIGUSR1 #用户自定义信号 默认处理:进程终止
- 14 SIGALRM #定时器到时后终止进程
- 17 SIGCHLD # 忽略
- 20 SIGTSTP #使进程暂停
- 查看Linux中64种信号的命令:
-
他的典型使用就是一些封装好的命令,如
-
发送信号函数:kill、raise、alarm
kill pid 9
——杀死进程号为pid的进程raise(SIGTSTP);
——raise只能给当前进程发送信号alarm(8);
——alarm只能给当前进程发送SIGALRM信号,所以只用指定秒数
-
接收信号函数:pause、sleep;
-
信号处理函数:signal。前面的都是内核自动处理接收到的信号,而signal函数可以自定义内核如何处理接收到的信号
#include "stdio.h" #include "sys/types.h" #include "signal.h" #include "stdio.h" #include "stdlib.h" #include <unistd.h> void myfunc(int signum) { for(int j=0;j<5;j++) { printf("Process processing signal,signum=%d\n",signum); } return; //返回main函数 } int main() { signal(14,myfunc); printf("alarm signal before\n"); alarm(8);; printf("alarm signal after\n"); for(int i=0;i<15;i++) { printf("process running,i=%d\n",i); sleep(1); } return 0; } /*#include <signal.h> void (*signal(int signum, void(*handler)(int)))(int); A=void(*handler)(int)):函数指针,指向了有一个int型的参数,无返回值的函数 void (*signal(int signum, A)(int); 所以,signal函数是,参数有两个,其中一个是函数指针,返回值是函数指针 参数一:signum :处理哪个信号 参数二:如何处理 SIG_IGN:忽略该信号 SIG_DFL:采用系统默认方式处理信号 自定义 */
-
IPC通信
- 删除ipc对象
ipcrm -m id //删除共享内存 ipcrm -q id //删除消息队列 ipcrm -s id //删除信号灯
- 查看ipc对象
ipcs -m id //查看共享内存 ipcs -q id //查看消息队列,字节数会包括换行 ipcs -s id //查看信号灯
共享内存
- 共享内存(shared memory)也是在内核中存在的对象,它不会像管道一样读完就删除内容
- 重要函数
- shmget()函数创建共享内存
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_ t key, int size, int shmflg); /*key: IPC_PRIVATE:key值为0,只能实现亲缘关系进程间的通信 ftok函数创建key值:不为0,能实现无亲缘关系进程间的通信 size:共享内存区大小 shmflg:权限,也可以用8进制表示法 成功:返回一个整型shmid,是共享内存的段标识符*/ key_t ftok(const char *pathname, int proj_id) /*pathname:指定的文件,此文件必须存在且可存取 proj_id:键值 成功:返回key值 */
- 如果用read/write的话,每次都要进入内核,麻烦,所以系统提供了shmat函数,用于内存映射。
将内存中的共享内存映射到用户空间
父子进程都要映射void *shmat (int shmid, const void *shmaddr, int shmflg); /*第一个参数: ID号; 第二个参数:映射到的地址,NULL为系统自动完成的映射; 第三个参数shmflg: SHM_ RDONLY共享内存只读 默认是0,表示共享内存可读写 返回值:成功:映射后的地址; 失败: NULL. */
- 映射到用户空间的内存和内核空间的内存都要释放
int shmdt(const void *shmaddr); /*shmaddr;共享内存映射后的地址 返回值:成功: 0 出错: -1 */ int shmctl(int shmid, int cmd,struct shmid ds *buf); /*进入内核 shmid: 要操作的共享内存标识符(shmget的返回值) cmd: IPC_STAT (获取对象属性)——实现了命令ipcs -m IPC_SET (设置对象属性) IPC_RMID (删除对象)——实现了命令ipcrm -m id buf :指定IPC_STAT/IPC_SET时用以保存/设置属性;IPC_RMID时为NULL 函数返回值:成功: 0 出错: -1 */
- shmget()函数创建共享内存
- 代码实现:
- shmget创建共享内存:
- 创建key值为0,只能实现亲缘关系进程通信的共享内存
#include <sys/ipc.h> #include <sys/shm.h> #include "stdio.h" //1. shmget创建ipc对象——共享内存; int main() { int shmid; shmid=shmget(IPC_PRIVATE,128,0777); printf("shmid=%d\n",shmid); return 0; }
- 创建key值不为0,能实现无亲缘关系进程通信的共享内存
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "stdio.h" //2. fork创建ipc对象——共享内存; int main() { int shmid; int key; key=ftok("./shmget.c",'a'); //创建键值a,用于区分不同的共享内存。不同的共享内存建议创建不同的键值用以区分 printf("key=%d\n",key); shmid=shmget(key,128,0777); printf("shmid=%d\n",shmid); return 0; }
- 创建key值为0,只能实现亲缘关系进程通信的共享内存
- shmat内存映射
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "stdio.h" int main() { char *p; //映射后的地址 int shmid; shmid=shmget(IPC_PRIVATE,128,0777); printf("shmid=%d\n",shmid); p=(char *)shmat(shmid,NULL,0); //是void*类型,强制转换为char*类型 printf("p=%s\n",p); //空的 //fgets原型fgets (char *__restrict __s, int __n, FILE *__restrict __stream) fgets(p,128,stdin); //键盘输入 //从内存读 printf("p=%s\n",p); printf("p=%s\n",p); //读完之后再读 return 0; }
- shmdt、shmctl释放内存
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "stdio.h" int main() { char *p; //映射后的地址 int shmid; shmid=shmget(IPC_PRIVATE,128,0777); printf("shmid=%d\n",shmid); p=(char *)shmat(shmid,NULL,0); //是void*类型,强制转换为char*类型 printf("p=%s\n",p); //空的 //向内存写 fgets(p,128,stdin); //键盘输入 //从内存读 printf("p=%s\n",p); shmdt(p); shmctl(shmid,IPC_RMID,NULL); return 0; }
- 利用共享内存实现父子进程通信,要求:父进程向内存写一次数据,子进程就从中读一次
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "stdio.h" #include <unistd.h> #include <string.h> #include <signal.h> void myfunc(int signum) { return; } int main() { pid_t pid; int shmid; char *p; shmid=shmget(IPC_PRIVATE,128,0777); if(shmid<0) { printf("Failed to create shared memory!\n"); return -1; } printf("shared memory's shmid=%d!\n",shmid); pid=fork(); if(pid<0) { printf("Failed to create child process!\n"); return -1; } if(pid>0) //父进程 { signal(SIGUSR2,myfunc); p=(char *)shmat(shmid,NULL,0); //映射 while (1) { printf("Please input :"); fgets(p,128,stdin); kill(pid,SIGUSR1); //给子进程发送SIGUSR1信号,开始读 pause(); } } if(pid==0) //子进程 { p=(char *)shmat(shmid,NULL,0); //子进程也要映射!!! signal(SIGUSR1,myfunc); while (1) { pause(); //睡眠 printf("shared memory data is:%s",p); kill(getppid(),SIGUSR2); //给父进程发送SIGUSR2信号,读完 } } shmdt(p); shmctl(shmid, IPC_RMID, NULL); return 0; }
- 利用共享内存实现非父子进程通信。要求:进程2写一次,进程1就读一次
-
进程1代码
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "stdio.h" #include <unistd.h> #include <string.h> #include <signal.h> struct mybuf { int pid; char buf[124]; }; void myfunc(int signum) { return; } int main() { pid_t pid; int shmid,key; struct mybuf *p; key=ftok("./a.c",'a'); shmid=shmget(key,128,IPC_CREAT|0777); if(shmid<0) { printf("Failed to create shared memory!\n"); return -1; } printf("shared memory's shmid=%d!\n",shmid); signal(SIGUSR1,myfunc); p=(struct mybuf *)shmat(shmid,NULL,0); //映射 pid=p->pid; //读服务端写入的pid p->pid=getpid(); //进程1的pid写到共享内存 kill(pid,SIGUSR2); //给进程2发送SIGUSR2信号,唤醒进程2 //循环读取 while (1) { pause(); printf("client receive data :%s",p->buf); kill(pid,SIGUSR2); //给服务端进程发送SIGUSR2信号,读完了,你可以写了 } shmdt(p); shmctl(shmid, IPC_RMID, NULL); return 0; }
-
进程2代码
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "stdio.h" #include <unistd.h> #include <string.h> #include <signal.h> struct mybuf { int pid; char buf[124]; }; void myfunc(int signum) { return; } int main() { pid_t pid; int shmid,key; struct mybuf *p; key=ftok("./a.c",'a'); shmid=shmget(key,128,IPC_CREAT|0777); if(shmid<0) { printf("Failed to create shared memory!\n"); return -1; } printf("shared memory's shmid=%d!\n",shmid); signal(SIGUSR2,myfunc); p=(struct mybuf *)shmat(shmid,NULL,0); //映射 p->pid=getpid(); //进程2的pid写到共享内存 pause(); //挂起进程,等待信号唤醒 pid=p->pid; //读进程1写入的pid while (1) { printf("Please input :"); fgets(p->buf,128,stdin); kill(pid,SIGUSR1); //给进程1发送SIGUSR1信号,唤醒进程1 pause(); } shmdt(p); shmctl(shmid, IPC_RMID, NULL); return 0; }
-
- shmget创建共享内存:
消息队列
-
管道队列是顺序队列,消息队列是链式队列
-
重要函数
- msgget创建消息队列(message queue):
#include <sys/tvpes.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int flag); /* 用法同shmget,但是参数没有size,链式队列不需要设置内存大小 */
- 关闭消息队列:msgctl,用法同shmctl
- msgsnd队列插入,相当于write
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msgid, const void *msgp, size t size, int flag); /* msgid:消息队列的ID msgp:指向消息的指针。常用消息结构msgbuf如下: struct msgbuf { long mtype; //消息类型 char mtext[N]; //消息正文 }; size: 发送的消息正文的字节数 flag: 非阻塞方式:IPC_ NOWAIT,消息没有发送完成函数也会立即返回。 阻塞方式:0:直到发送完成函数才返回 */
- msgrvc队列读取,相当于read
- msgget创建消息队列(message queue):
-
代码实现
-
msgget创建消息队列
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "stdio.h" #include "stdlib.h" int main() { int msgid; msgid= msgget(IPC_PRIVATE, 0777); if(msgid<0) { printf("msgget failed!\n"); return -1; } printf("msgid=%d\n",msgid); return 0; }
-
msgctl释放消息队列
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "stdio.h" #include "stdlib.h" int main() { int msgid; msgid= msgget(IPC_PRIVATE, 0777); if(msgid<0) { printf("msgget failed!\n"); return -1; } printf("msgid=%d\n",msgid); system("ipcs -q"); msgctl(msgid,IPC_RMID,NULL); system("ipcs -q"); return 0; }
-
msgsnd发送信息给消息队列
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "stdio.h" #include "stdlib.h" #include <string.h> struct msgbuf { long mtype; char mtext[128]; }; int main() { int msgid; struct msgbuf sendbuf; msgid= msgget(IPC_PRIVATE, 0777); //创建队列 if(msgid<0) { printf("msgget failed!\n"); return -1; } printf("msgid=%d\n",msgid); system("ipcs -q"); //初始化结构体 sendbuf.mtype=100; printf("Please input message:\n"); fgets(sendbuf.mtext,128,stdin); //发送消息 msgsnd(msgid,(void*)&sendbuf,strlen(sendbuf.mtext),0); system("ipcs -q"); msgctl(msgid,IPC_RMID,NULL); //删除队列 return 0; }
-
msgrvc读取消息队列中的消息
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "stdio.h" #include "stdlib.h" #include <string.h> struct msg_sndbuf { long mtype; char mtext[128]; }; struct msg_rcvbuf { long mtype; char mtext[128]; }; int main() { int msgid,byte_longth; struct msg_sndbuf sendbuf; struct msg_sndbuf rcvbuf; msgid= msgget(IPC_PRIVATE, 0777); //创建队列 if(msgid<0) { printf("msgget failed!\n"); return -1; } printf("msgid=%d\n",msgid); //初始化结构体 sendbuf.mtype=111; strcpy(sendbuf.mtext, "linux"); //发送消息 msgsnd(msgid,(void*)&sendbuf,strlen(sendbuf.mtext),0); //接收消息 byte_longth=msgrcv(msgid,(void *)&rcvbuf,128,111,0); printf("receive message is:%s\n",rcvbuf.mtext); printf("byte_longth is: %d\n",byte_longth); msgctl(msgid,IPC_RMID,NULL); //删除队列 return 0; }
-
消息队列实现两个无亲缘关系进程间的通信:要求进程A循环从键盘读入要写到消息队列的内容,进程B读
- 进程A代码
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "stdio.h" #include "stdlib.h" #include <string.h> struct msg_sndbuf { long mtype; char mtext[128]; }; int main() { int msgid,byte_longth,key; struct msg_sndbuf sendbuf; key=ftok("./05_A_write",'a'); msgid= msgget(key,IPC_CREAT|0777); //创建队列 if(msgid<0) { printf("msgget failed!\n"); return -1; } printf("msgid=%d\n",msgid); //初始化结构体 sendbuf.mtype=111; while (1) { printf("Please enter the information you want to send:"); fgets(sendbuf.mtext,128,stdin); //发送消息 msgsnd(msgid,(void*)&sendbuf,strlen(sendbuf.mtext),0); } return 0; }
- 进程B代码,要注意的是,进程B也需要进行ftok和msgget操作,并且每一次读取完成后/前需要清除掉上一次读取的内容,否则会影响下一次读取。写操作完成后不用进行清除,因为消息队列读完后内容就没了
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "stdio.h" #include "stdlib.h" #include <string.h> struct msg_rcvbuf { long mtype; char mtext[128]; }; int main() { int msgid,key; struct msg_rcvbuf rcvbuf ; key=ftok("./05_A_write",'a'); msgid= msgget(key,IPC_CREAT|0777); //创建队列 if(msgid<0) { printf("msgget failed!\n"); return -1; } while (1) { memset(rcvbuf.mtext,0,128); //清除缓存 //接收消息 msgrcv(msgid,(void *)&rcvbuf,128,111,0); printf("receive message is:%s",rcvbuf.mtext); } return 0; }
- 进程A代码
-
实现两个非亲缘关系进程同时收发的双向通信(利用父子进程分别读写实现)
-
信号灯
- 信号量的集合
- 重要函数
- semget创建信号灯
#include <sys/types.h>+ #include <sys/ipc.h>s #include <sys/sem.h>p int semget(key t key, int nsems, int semflg); 用法同shmget /*key:和信号灯集关联的key值 nsems:信号灯集中包含的信号灯数目 semflg:信号灯集的访问权限 返回值 成功:信号灯集ID 出错: -1 */
- semctl删除信号灯
#include <sys/types.h>v #include <sys/ipc.h>s #include <sys/sem.h>. int semctl ( int semid, int semnum, int cmd, ..union semun arg); /* semid: 信号灯集ID. semnum: 要修改的信号灯编号(此参数在做删除用时随便写) emd: GETVAL:获取信号灯的值。 SETVAL:设置信号灯的值。 IPC_RMID:从系统中删除信号灯集合 semun arg:不是地址 返回值: 成功: 0 出错: -1 */
- semget创建信号灯
- 代码实现:
- semget创建信号灯、semctl删除信号灯
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include "stdio.h" #include "stdlib.h" int main() { int semid; semid=semget(IPC_PRIVATE,3,0777); if(semid<0) { printf("semget failed!\n"); return -1; } printf("semid=%d\n",semid); system("ipcs -s"); semctl(semid,0,IPC_RMID); system("ipcs -s"); return 0; }
- semget创建信号灯、semctl删除信号灯