无名管道只能实现有亲缘关系的进程之间的通信,比如父子进程。
pipe函数:
#includeint pipe(int pipefd[2]);//创建管道
例程1参数:是我们得到的文件描述符
- fd[0]: 读端
- fd[1]: 写端
返回值:
- 成功创建返回0
- 创建失败返回-1.
#include有名管道#include #include #include #include #include int main(void) { pid_t pid; int fd[2]; char buf[32] = {0}; // 在fork函数之前创建管道 pipe(fd); printf("fd[0] is %dn", fd[0]); printf("fd[1] id %dn", fd[1]); pid = fork(); if (pid < 0) { printf("fork errorn"); return -1; } // 父进程 if (pid > 0) { int status; close(fd[0]); write(fd[1], "hello", 5); close(fd[1]); wait(&status); exit(0); } // 子进程 if (pid == 0) { close(fd[1]); read(fd[0], buf, 32);//阻塞读 printf("buf is %sn", buf); close(fd[0]); exit(0); } }
有名管道可以实现两个互不相关的进程间通信。
mkfifo 函数
#include#include int mkfifo(const char *pathname, mode_t mode);
例程2参数:是我们得到的文件描述符
- pathname: 路径
- mode: 读写模式
返回值:
- 成功创建返回0
- 创建失败返回-1.
fifo_read.c
#include#include #include #include #include #include #include int main(int argc, char *argv[]) { char buf[32] = {0}; int fd; if (argc < 2) { printf("Usage: %s n", arg[0]); return -1; } fd = open(argv[1], O_RDONLY); while (1) { sleep(1); read(fd, buf, 32); printf("buf is $sn", buf); memset(buf, 0, sizeof(buf)); } close(fd); return 0; }
fifo_write.c
#include信号通信#include #include #include #include #include int main(int argc, char *argv[]) { int ret; int fd; if (argc < 2) { printf("Usage: %s n", argv[0]); return -1; } if (access(argv[1], F_OK) == -1) // 判断argv[1]传入的文件是否存在 { ret = mkfifo(argv[1], 0666); if (ret == -1) { printf("mkfifo errorn"); return -2; } printf("mkfifo okn"); } fd = open(argv[1], O_WRONLY); while (1) { sleep(1); write(fd, "hello", 5); } close(fd); return 0; }
可以通过命令* " kill -l " *查看系统中有哪些信号。
信号发送函数kill函数:
#include#include int kill(pid_t pid, int sig);
raise函数:
#includeint raise(int sig);
raise函数等价于kill(getpid(), sig);
alarm函数:
设置一个时间值,当设置的时间到了就产生一个信号。
#include例程3unsigned int alarm(unsigned int seconds);
// 9号信号是“不能被捕获的进程终止信号”,进程接收到信号后默认操作是“终止进程”。 // 这个程序只会打印 "raise beforen" #include例程4#include #include #include #include int main(void) { printf("raise beforen"); raise(9); printf("raise aftern"); return 0; }
kill.c
// 用法与“kill 命令用法相同” #include#include #include #include #include int main(int argc, char *argv[]) { pid_t pid; int sig; if (argc < 3) { printf("Usage:%s n", argv[0]); return -1; } sig = atoi(argv[2]); pid = atoi(argv[1]); kill(pid, sig); return 0; }
test.c 一秒钟打印一句helloworld
// 先运行test.c // 使用 " ps aux | grep ./test " 查看pid号 // 运行kill,发送信号到 test进程。 #include例程5#include int main(void) { while(1) { printf("hello worldn"); sleep(1); } return 0; }
// 设置时间3秒,时间值到了以后,发送信号"SIGALRM",默认操作是终止该进程 #include信号通信 信号接收函数#include #include #include #incldue < stdlib.h> int main(int argc, char *argv[]) { int i; alarm(3); while (1) { sleep(1); i++; printf("i = %dn", i); } return 0; }
如果一个进程要接收信号,需要这个进程不停止。一共有三种方式实现:
- while 循环
- sleep 函数
- pause 函数
pause函数:
#include信号的处理int pause(void); // pause() 会令目前的进程暂停(进入睡眠状态),直到被信号(signal)所中断。 // 返回值:只返回-1
信号处理的三种方式:系统默认,忽略,捕获
signal函数:
#includetypedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); // 可以简化成: // signal(参数1,参数2); // 参数1:我们要进行处理的信号,系统的信号我们可以在终端键入 kill -l 查看。 // 参数2:处理的方式(是系统默认还是忽略还是捕获)。
三个例子:
“SIGINT” 信号由“ctrl+c”产生。
- signal(SIGINT, SIG_IGN);
- SIG_IGN,代表忽略,也就是忽略SIGNT信号
- signal(SIGINT, SIG_DFL);
- SIG_DFL代表执行系统默认操作,大多数信号的系统默认动作是终止该进程
- signal(SIGINT, myfun);
- 捕捉SIGINT这个信号,然后执行myfun函数里面的代码。myfun由我们自己定义。
#include例程7#include #include int main(void) { signal(SIGINT, SIG_IGN); //忽略2号信号,ctrl+c无法终止该进程 //signal(SIGINT, SIG_DFL);//系统默认的处理方式 while (1) { printf("wait signaln"); sleep(1); } return 0; }
#include共享内存#include #include void myfun(int sig) { if (sig == SIGINT) // 接收到“ctrl+c”打印“get signaln” { printf("get signaln"); } } int main(void) { signal(SIGINT, myfun);// 接收到2号信号,执行myfun函数 // 接收到其他信号,不会忽略,也不会执行myfun函数 while (1) { printf("wait signaln"); sleep(1); } return 0; }
- shmget函数,创建共享内存
#include#include int shmget(key_t key, size_t size, int shmflg);
- 参数:
- key_t key: IPC_PRIVATE或者是ftok函数的返回值
- size_t size: 共享内存的大小
- int shmflg: 权限
- 返回值:
- 成功返回共享内存的标识符,失败返回-1
#include#include #include int main(void) { int shmid; shmid = shmget(IPC_PRIVATE, 1024, 0777); if (shmid < 0) { printf("shmget is errorn"); return -1; } printf("shmget is ok and shmid is %dn", shmid); return 0; }
可以通过命令 ipcs -m 查看是否创建成功
可以使用命令 ipcrm -m ${shmid} 删除
ftok函数
#include#include key_t ftok(const char *pathname, int proj_id);
- 参数:
- const char *pathname 文件路径以及文件名
- int proj_id 字符
- 返回值
- 成功返回key值,失败返回-1
#include#include #include #include int main(void) { int shmid; key_t key; key = ftok("./a.c", 'a'); shmid = shmget(key, 1024, 0777 | IPC_CREAT);// 使用ftok函数返回值时,需要加上IPC_CREAT权限,否则创建失败 if (shmid < 0) { printf("shmget is errorn"); return -1; } printf("shmget is ok and shmid is %dn", shmid); return 0; }
两种创建方式的区别,如果使用IPC_PRIVATE作为第一个参数,创建的共享内存,key值是0,如果使用ftok函数返回值创建,key值不是0。
shmat函数,创建共享内存用户空间的地址映射
#include#include void *shmat(int shmid, const void *shmaddr, int shmflg);
- 参数:
- int shmid: 共享内存的标识符,也就是shmget函数的返回值
- const void *shmaddr: 映射到的地址,一般写NULL,NULL为系统自动帮我们完成映射
- int shmflg: 通常为0,表示共享内存可读可写,或者为SHM_RDONLY,表示共享内存只读
- 返回值:
- 成功返回共享内存映射到进程中的地址,失败返回-1
shmdt函数,将进程里的共享内存地址映射删掉
#include#include int shmdt(const void *shmaddr);
- 参数:
- const void *shmaddr: 共享内存映射后的地址
- 返回值:
- 成功返回0,失败返回-1
注意:shmdt函数是将进程中的地址映射删除,也就是说当一个进程不需要共享内存的时候,就可以使用这个函数将他从进程地址空间中脱离,并不会删除内核里面的共享内存对象。
shmctl函数,删除共享内存
#include#include int shmctl(int shmid, int cmd, struct shmid_ds buf);
- 参数:
- int shmid: 要操作的共享内存的标识符
- int cmd: IPC_STAT(获取对象属性)IPC_SET(设置对象属性) IPC_RMId(删除对象)
- struct shmid_ds *buf: 指定 IPC_STAT(获取对象属性) IPC_SET(设置对象属性)时用来保存或者设置的属性
- 返回值:
- 成功返回0,失败返回-1
#include消息队列#include #include #include #include #include #include #include int main(void) { int shmid; key_t key; pid_t pid; char *s_addr, *p_addr; key = ftok("./a.c", 'a'); shmid = shmget(key, 1024, 0777 | ICP_CREATE); if (shmid < 0) { printf("shmget is errorn"); return -1; } printf("shmget is ok and shmid is %dn", shmid); pid = fork(); if (pid > 0) { p_addr = shmat(shmid, NULL, 0); strncpy(p_addr, "hello", 5); wait(NULL); exit(0); } if (pid == 0) { sleep(2); s_addr = shmat(shmid, NULL, 0); printf("saddr is %sn", s_addr); exit(0); } return 0; }
- 创建消息队列
- 向消息队列发送消息
- 接收消息队列中的消息
msgget函数:创建消息队列
#include#Include #include int msgget(key_t key, int msgflg);
- 参数:
- key_t key: 和消息队列相关的key值
- int msgflg: 访问权限
- 返回值:
- 成功返回消息队列的ID,失败返回-1
msgctl函数:删除消息队列
#include#include #include int msgctl(int msqid, int cmd, struct msqid_ds *buf);
- 参数:
- int msqit: 消息队列的ID
- int cmd:
- IPC_STAT: 读取消息队列的属性,然后把它保存在buf指向的缓冲区。
- IPC_SET: 设置消息队列的属性,这个值取自buf参数
- IPC_RMID: 删除消息队列
- struct msqit_ds *buf: 消息队列的缓冲区
- 返回值:
- 成功返回0,失败返回-1
#include#include #include #include int main(void) { int msgid; key_t key; key = ftok("./a.c", 'a'); msgid = msgget(key, 0666 | IPC_CREAT); if (msgid < 0) { printf("msgget is errorn"); } printf("msgget is ok and msgid is %dn", msgid); return 0; }
可以使用命令 tpcs -q 查看消息队列是否创建成功
msgsend函数:向消息队列发送消息
#include#include #include int msgsend(int msqid, const void *msgp, size_t msgsz, int msgflg);
- 参数:
- int msqid: 消息队列ID
- const void *msgp: 指向消息类型的指针
- size_t msgsz: 发送的消息的字节数
- int msgflg:
- 如果为0,直到发送完成函数才返回,即阻塞发送
- IPC_NOWAIT: 消息没有发送完成,函数也会返回,即非阻塞发送
- 返回值:
- 成功返回0,失败返回-1
消息结构体,上文所述的发送的消息的字节数,仅包含消息内容‘mtext’的长度
struct msgbuf {
long mtype;//消息类型
char mtext[1]; //消息内容
}
msgrcv函数,接收消息
#include#include #include ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
- 参数:
- int msqid: 消息队列ID
- void *msgp: 接收消息的缓冲区
- size_t msgsz: 接收消息的字节数
- long msgtyp: 接收消息的标识,0表示接收消息队列中的第一个消息
- int msgflg:
- 0表示阻塞读取
- IPC_NOWAIT表示非阻塞读取
- 返回值:
- 成功返回接收到的消息长度,失败返回-1
消息队列写
#include#include #include #include #include struct msgbuf { long mtype; char mtext[128]; }; int main(void) { int msgid; key_t key; struct msgbuf msg; key = ftok("./a.c", 'a'); msgid = msgget(key, 0666 | IPC_CREAT); if (msgid < 0) { printf("msgget is errorn"); } printf("msgget is ok and msgid is %dn", msgid); msg.mtype = 1; strncpy(msg.mtext, "hello", 5); msgsnd(msqid, &msg, strlen(msg.mtext), 0); return 0; }
消息队列读
#include信号量#include #include #include #include struct msgbuf { long mtype; char mtext[128]; }; int main(void) { int msgid; key_t key; struct msgbuf msg; key = ftok("./a.c", 'a'); msgid = msgget(key, 0666 | IPC_CREAT); if (msgid < 0) { printf("msgget is errorn"); } printf("msgget is ok and msgid is %dn", msgid); msgrcv(msgid, &msg, 128, 0, 0); printf("msg.mtype is %ldn", msg.mtype); printf("msg.mtext is %sn", msg.mtext); return 0; }
信号量不以传输数据为主要目的,他的主要作用是保护共享资源。
semget函数,获取信号量的ID
#include#include #include int semget(key_t key, int nsems, int semflg);
- 参数:
- key_t key: 信号量的键值。
- int nsems: 信号量的数量
- int semflg: 标识(权限)
- 返回值:
- 成功返回信号量的ID
- 失败返回-1
semctl函数
#include#include #include int semctl(int semid, int semnum, int cmd, union semun arg);
- 参数:
- int semid: 信号量ID
- int semnum: 信号量编号
- int cmd:
- IPC_STAT 获取信号量的属性
- IPC_SET 设置信号量的属性
- IPC_RMID 删除信号量
- SETVAL 设置信号量的值
- arg: union semun {
- int val;
- struct semid_ds *buf;
- unsigned short *array;
- struct seminfo * __buf;
- 返回值:
- 成功返回0,失败返回-1
semop函数
#include#include #include int semop(int semid, struct sembuf *sops, size_t nsops);
- 参数:
- int semid: 信号量ID
- struct sembuf *sops: 信号量结构体数组
- size_t nsops 要操作信号量的数量
sturct sembuf {
unsigned short sem_num; //要操作的信号量的编号
short sem_op; //P/V操作,1为V操作,释放资源。-1为P操作,分配资源。0为等待,直到信号量的值变成0
short sem_flg;//0表示阻塞,IPC_NOWAIT表示非阻塞
}
例程13
#include暑期编程PK赛 得CSDN机械键盘等精美礼品!#include #include #include #include union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *buf; }; int main(void) { int semid; int key; union semun semun_union; pid_t pid; struct sembuf sem; key = ftok("./a.c", 0666); semid = semget(key, 1, 0666 | IPC_CREAT); semun_union.val = 0; semctl(semid, 0, SETVAL, semun_union); pid = fork(); if (pid > 0)// 父进程 { sem.sem_num = 0; sem.op = -1; sem.flg = 0; semop(semid, &sem, 1); printf("This is parentsn"); } if (pid == 0)// 子进程 { sleep(2); sem.sem_num = 0; sem.op = 1; sem.flg = 0; semop(semid, &sem, 1); printf("This is sonn"); } return 0; }



