使用文件实现进程间通信
实现功能:
- 实现从数字1到数字N的累加
filename : sum.c,可执⾏程序sum
Usage : ./sum -i 5 -n 10000 : 表⽰使⽤5个进程,计算从1加到10000的和
Result :1+2+3+…+10000 = ?
- 每个进程都参与计算
- 不能对业务进⾏拆分
- 每个进程都去抢着加
- 不能使⽤任何睡眠策略
- 不能规定进程的执⾏顺序
- 需要使⽤⽂件,参考flock的⽤法
代码实现:
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/file.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#define BUF_LEN 64
int main()
{
char buf[BUF_LEN] = "0 1";
int i = 1, temp = 0, pid;// i:当前待累加值,temp,当前累加结果
int fd = open("./sum", O_RDWR |O_CREAT | O_TRUNC, 0777);
if(fd < 0)
{
perror("open");
exit(0);
}
write(fd, buf, BUF_LEN);
//用父进程分别创建出五个子进程
for(int j = 1; j <= 5; j++)
{
pid = fork();
if(pid < 0)
{
perror("fork");
exit(1);
}
if(!pid) break;
}
if(pid)
{
//记得处理子进程僵尸进程
for(int j = 1; j <= 5; j++)
waitpid(0, NULL, 0);
//打印结果
lseek(fd, 0, SEEK_SET);
if(read(fd, buf, BUF_LEN) < 0)
{
perror("read");
exit(1);
}
sscanf(buf, "%d %d", &temp, &i);
//printf("%s\n", buf);
printf("sum = %d\n", temp);
close(fd);
}
else
{
//记得要重新调用open
//否则因为子进程与父进程共享同一个文件打开表而导致互斥锁失效
close(fd);
fd = open("./sum", O_RDWR);
while(1)
{
if(flock(fd, LOCK_EX) != 0)
{
perror("flock");
exit(1);
}
//输出调试信息1
//printf("pid:[%d] arrive.\n", getpid());
lseek(fd, 0, SEEK_SET);
if(read(fd, buf, BUF_LEN) < 0)
{
perror("read");
exit(1);
}
sscanf(buf, "%d %d", &temp, &i);
//输出调试信息2
//printf("%d\n", i);
if(i > 1000)
{
close(fd);
exit(0);
}
temp += i++;
sprintf(buf, "%d %d", temp, i);
//printf("pid:[%d] %s\n", getpid(), buf);
lseek(fd, 0, SEEK_SET);
if(write(fd, buf, BUF_LEN) < 0)
{
perror("write");
exit(1);
}
if(flock(fd, LOCK_UN) < 0)
{
perror("flock_UN");
exit(1);
}
}
}
return 0;
}
心得:
踩了亿些坑 - -…,百度csdn找了好多份资料结果发现还是man手册香啊啊啊(虽然全英不友好)。
- PCB中保存着文件描述符表,调用fork创建子进程时子进程会继承复制一份文件描述符表到其PCB中。
- 文件描述符表指向文件打开描述符表,调用fork创建子进程时子进程和父进程共享同一份文件打开描述符表。
- 文件锁相关信息保存在文件打开描述符表中,若子进程用父进程的文件描述符对某文件进行互斥访问的话,会因为共享同一份文件打开描述符而导致互斥锁失效。