实现这么一个程序:
从磁盘上读取文件,对文件内容解析,解析出两个加数,生成一个可以执行加法运算的动态库,调用该动态库进行加法计算,再将计算结果写入共享内存,然后创建子进程,子进程进行程序替换,替换的程序要完成的任务就是将共享内存中的内容重新写回磁盘上的该文件,记得使用共享内存时要借助信号量保证互斥操作。
具体过程如下图:
代码实现:
add.h
#ifndef __ADD_H__
#define __ADD_H__
int add(int left,int right);
#endif//__ADD_H__
add.c
#include "add.h"
int add(int left,int right)
{
return left+right;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include "add.h"
void handler(int s)
{
wait(NULL);
exit(0);//子进程结束后父进程也应该退出,不然父进程一直死循环
}
int main()
{
signal(SIGCHLD,handler);
//读取tmp文件
int fd=open("tmp",O_RDONLY);
if(fd==-1)
{
perror("open");
exit(1);
}
int r;
char buf[100];
memset(buf,0x00,sizeof(buf));
label:
r=read(fd,buf,sizeof(buf));//不能在label下定义变量,因为有可能不能执行到该处
if(r==-1)
{
if(errno==EINTR)//有可能被信号打断,打断后应该回到上面继续去读
goto label;
perror("read");
}
close(fd);
//调用add函数计算加法
int left,right;
sscanf(buf,"%d+%d",&left,&right);//格式化解析字符串
r=add(left,right);
//将计算结果写入共享内存
memset(buf,0x00,sizeof(buf));
sprintf(buf,"%d+%d=%d\n",left,right,r);
int shmid=shmget(1234,strlen(buf),IPC_CREAT|0644);//创建共享内存
char *addr=shmat(shmid,NULL,0);//将共享内存挂载到该进程的地址空间
int semid=semget(1234,1,IPC_CREAT|0644);//创建信号量
union semun{ int val;};
union semun su={1};
semctl(semid,0,SETVAL,su);//信号量设初值
struct sembuf sbp[]={{0,-1,0}};
struct sembuf sbv[]={{0,1,0}};
semop(semid,sbp,1);//上锁
memcpy(addr,buf,strlen(buf));//将数据写入共享内存段,实际工作中一般用memcpy进行拷贝,可以限定addr的大小,安全
semop(semid,sbv,1);//解锁
shmdt(addr);//卸载共享内粗
//创建子进程,让子进程调用mywrite程序,将结果写入程序
pid_t pid=fork();
if(pid==-1)
{
perror("fork");
exit(1);
}
if(pid==0)
{
char *argv[]={"mywrite",NULL};
execvp("./mywrite",argv);
perror("execvp");//执行到该处说明mywrite不存在,execvp执行失败
exit(1);
}
for(;;)
{
pause();
}
}
write.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdlib.h>
int main()
{
//读共享内存
char buf[100];
int shmid=shmget(1234,0,0);//打开共享内存
char *addr=shmat(shmid,NULL,0);//挂载到该进程的虚拟地址空间
int semid=semget(1234,1,0);//打开信号量集
memset(buf,0x00,sizeof(buf));
struct sembuf sbp[1]={{0,-1,0}};
struct sembuf sbv[1]={{0,1,0}};
//上锁
semop(semid,sbp,1);
memcpy(buf,addr,strlen(addr));
semop(semid,sbv,1);
//解锁
shmdt(addr);
//写文件
int fd=open("./tmp",O_TRUNC|O_WRONLY);
if(fd==-1)
{
perror("open");
}
write(fd,buf,strlen(buf));
close(fd);
shmctl(shmid,IPC_RMID,0);
semctl(shmid,0,IPC_RMID);
}
makefile
.PHONY:all clean
all:main mywrite
main:main.o libadd.so
gcc $< -o $@ -L. -ladd
libadd.so:add.c
gcc -fPIC -shared -o $@ $<
mywrite:mywrite.o
gcc $^ -o $@
%.o:%.c
gcc -c $< -o $@
clean:
rm -rf *.o mywrite main