进程间协作、同步
来源:互联网 发布:mac梦幻西游文件夹 编辑:程序博客网 时间:2024/05/20 04:50
进程和进程之间无非是通过磁盘、内核、用户空间传输数据。
通过磁盘(也就是文件)实现进程通信这个好理解,服务器进程把计算结果写入文件,客户端进程从文件读数据就可以了。这里的竞争条件是当服务端正在写文件时,客户端是不允许读的。
命名管道把数据写入文件,因此它可以独立于进程存在。但是命名管道是一个队列而非常规的文件,当读者把数据读走后,数据就不存在了,下一次读到的是后面的内容。
普通管道位于内核,用于父子进程间通信,因此它的存在依赖于进程的存在。
进程间通过文件或FIFO传输数据时,write将数据从内存复制到内核缓冲区,read将数据从内核缓冲区复制到内存。而使用共享内存是不存在用户空间和内核空间的来回复制的。共享内存段是用户内存的一部分,不同的进程都拥有指向此内存段的指针。进程依靠访问权限来对这段内存进行读或写。
上面已提到通过文件实现进程间通信时需要对进程进行同步,用到文件锁。
下面的代码服务端负责向文件写入当前时间,客户端读取该文件。
服务端:
#include<sys/file.h>#include<stdio.h>#include<fcntl.h>#include<time.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#define oops(m,x) {\ perror(m); \ exit(x); \}main(int argc,char *argv[]){ int fd; time_t now; char* message; if(argc!=2){ fprintf(stderr,"usage:%s filename\n",argv[0]); exit(1); } if((fd=open(argv[1],O_CREAT|O_TRUNC|O_WRONLY,0644))==0) oops(argv[1],2); void lock_opreation(int,int); while(1){ time(&now); message=ctime(&now); if(lseek(fd,0,SEEK_SET)==-1) oops("lseek",3); lock_operation(fd,F_WRLCK); if(write(fd,message,strlen(message))==-1) oops("write",4); lock_operation(fd,F_UNLCK); sleep(1); }}lock_operation(int fd,int op){ struct flock lock; lock.l_whence=SEEK_SET; lock.l_start=0; lock.l_len=0; lock.l_pid=getpid(); lock.l_type=op; if(fcntl(fd,F_SETLKW,&lock)==-1) oops("locl operation",6);}
客户端:
#include<sys/file.h>#include<stdio.h>#include<fcntl.h>#include<time.h>#include<stdlib.h>#include<string.h>#define oops(m,x) {perror(m);exit(x);}#define BUFSIZE 50main(int argc,char *argv[]){ int fd,nread; char buf[BUFSIZE]; if(argc!=2){ fprintf(stderr,"usage:%s filename\n",argv[0]); exit(1); } if((fd=open(argv[1],O_RDONLY))==-1) oops(argv[1],2); while(1){ lock_operation(fd,F_RDLCK); //读锁 nread=read(fd,buf,BUFSIZE); lock_operation(fd,F_UNLCK); //解除读锁 if(nread>0){ printf("pid %d: %s",getpid(),buf); bzero(buf,BUFSIZE); } lseek(fd,0,SEEK_SET); sleep(3); } close(fd);}lock_operation(int fd,int op){ struct flock lock; lock.l_whence=SEEK_SET; lock.l_start=0; //锁住文件的起始位置 lock.l_len=0; //锁住的长度。0表示到文件结尾 lock.l_pid=getpid(); //哪个进程可能操作该文件 lock.l_type=op; //锁的类型。读、写or解锁 if(fcntl(fd,F_SETLKW,&lock)==-1) //通过fcntl给文件设置锁 oops("lock operation",6);}
使用共享内存的多个进程之间通过信号量来协同工作。信号量是一个内核变量,它是系统级的全局变量,可以被系统中的任何进程所访问。
下面的代码是服务端向共享内存写入当前时间:
#include<stdio.h>#include<sys/shm.h>#include<time.h>#include<sys/types.h>#include<stdlib.h>#include<string.h>#include<sys/sem.h>#include<signal.h>#define TIME_MEM_KEY 99#define TIME_SEM_KEY 9900#define SEG_SIZE ((size_t)100)#define oops(m,x) {perror(m);exit(1);}union semnum{ int val; struct semid_ds *buf; //信号量控制结构体 ushort *array;};int seg_id,semset_id;void clearup(int);main(){ char *mem_ptr,*ctime(); //变量和函数放在一起声明 time_t now; int n; seg_id=shmget(TIME_MEM_KEY,SEG_SIZE,IPC_CREAT|0777); //共享内存有自己单独的读写权限0777 if(seg_id==-1) oops("shmget",1); mem_ptr=shmat(seg_id,NULL,0); if(mem_ptr==(void*)-1) oops("shmat",2); semset_id=semget(TIME_SEM_KEY,2,0666|IPC_CREAT|IPC_EXCL); //产生一个信号量集合,容量为2 if(semset_id==-1) oops("semget",3); set_sem_value(semset_id,0,0); //设置第一个信号量的值 set_sem_value(semset_id,1,0); //设置第二个信号量的值 signal(SIGINT,clearup); //SIGINT信号到来时做一些清理工作 for(n=0;n<60;n++){ time(&now); printf("\tshm_ts2 waiting for lock\n"); wait_and_lock(semset_id); //锁住共享内存 printf("\tshm_ts2 updating memeory\n"); strcpy(mem_ptr,ctime(&now)); //向共享内存写入数据 release_lock(semset_id); //释放信号量 printf("\tshm_ts2 released lock\n"); sleep(1); } clearup(0);}void clearup(int n){ shmctl(seg_id,IPC_RMID,NULL); //删除共享内存 semctl(semset_id,0,IPC_RMID,NULL); //删除信号量}set_sem_value(int semset_id,int semnum,int val){ union semnum initval; initval.val=val; if(semctl(semset_id,semnum,SETVAL,initval)==-1) oops("semctl",4);}wait_and_lock(int semset_id){ struct sembuf actions[2]; //对信号量进行制作的结构体 actions[0].sem_num=0; //操作第1个信号量 actions[0].sem_flg=SEM_UNDO; //进程结束时,进程对信号量的操作将被撤销(信号量属于IPC对象,IPC对象是独立于进程的) actions[0].sem_op=0; //阻塞直到信号量变为0 actions[1].sem_num=1; actions[1].sem_flg=SEM_UNDO; actions[1].sem_op=+1; //信号量的值加1,表示要释放该信号控制的资源 if(semop(semset_id,actions,2)==-1) oops("semop:locking",10);}release_lock(int semset_id){ struct sembuf actions[1]; actions[0].sem_num=1; actions[0].sem_flg=SEM_UNDO; actions[0].sem_op=-1; //如果当前信号量的值小于1,则阻塞。否则减去1。表示要获得由该信号控制的资源 if(semop(semset_id,actions,1)==-1) oops("semop:unlocking",10);}
管道和socket也包含了锁机制。管道和socket其实也是保存数据的内存段,它将数据从源端复制到目的端。不同的是管道和socket中的锁是由内核,而不是进程来管理的。
- 进程间协作、同步
- Linux--父子进程同步协作
- 线程间的协作同步
- 同步队列协作线程
- 进程/线程间同步
- 进程/线程间同步
- 进程间同步 信号量
- 进程线程间同步
- 进程间同步问题
- linux进程间同步
- python进程间同步
- python进程间同步
- 进程间通信,同步
- 进程间同步
- 进程间同步
- Contiki开发8:进程协作
- 【Bash百宝箱】协作进程coproc
- 进程间通信和同步
- 信号通信
- execvp
- 环境
- I/O重定向和管道
- fdopen和popen
- 进程间协作、同步
- 多线程基础
- pthread_cond_wait的思考
- 用curses库和多线程画来回运动的字符串
- Win7下用IIS发布网站
- 为什么并行没有比串行快?
- 并行计算机硬件基础
- 并行计算性能分析
- C语言内存泄漏之free、valgrind、examine