linux-programming-note-6(基本进程间通信方法)

来源:互联网 发布:淘宝如何一元秒杀 编辑:程序博客网 时间:2024/05/16 19:43

 Chapter 9-------基本进程间通信方法控制多线程下对某个非共享资源的访问,最简单的方法是使用临时文件作为访问标志。首先进程判断临时文件是否存在,如果存在表明有进程占用了该资源。进程A------\ \|文件存在?---------资源进程B_______/使用文件实现进程互斥程序实例#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#include <errno.h>int get_access_right(int inq_interval,int retry_times,char* file_name){int fd,count;count=0;fd=creat(file_name,0);while(fd==-1 && errno==EACCES){printf("pid:%ld process try to get access right...\n",(long)getpid());if(++count<retry_times)sleep(inq_interval);else return -1;fd=creat(file_name,0);}close(fd);if(fd==-1) return 1;else return -1;}int release_right(char* file_name){int result;result=unlink(file_name);if(result==0) return 1;else return -1;}int main(int argc,char* argv[]){int retry_times,inq_interval;char* file_name;int len,count=0;if(argc!=4){printf("usages: %s retry_times inquire_interval file_name\n",argv[0]);return 1;}inq_interval=atoi(argv[2]);if(inq_interval<=0) {printf("illegal retry times\n"); return 1;}len=strlen(argv[3]);if(len==0) {printf("illegal file name\n"); return 1;}if(get_access_right(inq_interval,retry_times,argv[3])==1){while(count<5){printf("pid: %ld process is occupying the resource,circle %d\n",(long)getpid(),count);count++;sleep(inq_interval);}release_right(file_name);return 0;}elseprintf("pid: %ld process cannot access the resource .....retry %d times\n",(long)getpid(),retry_times);return 0;}--------------------------使用文件作为访问资源的标志的缺陷:1.限制了进程间信息量的传输2.对存储器的读写的效率远远的低于内存和CPU3.如果两个问题同时查询文件,执行结果unexpected(不可预测)4.如果进程不稳定崩溃了而没有删除标志文件,其他进程永远可以不能访问到资源Linux文件锁:修改文件属性来控制进程通信fcntl()head <unistd.h><fcntl.h>define int fcntl(int fd,int cmd);int fcntl(int fd,int cmd,long arg);int fcntl(int fd,int cmd,struct flock *lock);return suc:返回值依赖cmd参数 fail:-1 errno:yescmd:F_DUPFD(复制文件描述符) FD_CLOEXEC(文件描述符标志) F_GETFL F_SETFL(文件状态标志)F_GETLK / F_SETLK /F_SETLKW(非强制文件锁[advisory locking])struct flock{........short l_type; //锁类型 F_RDLCK . F_WRLCK. F_UNLCKshort l_whence;//l_start起始点 可以为SEEK_SET SEEK_CUR SEEK_ENDoff_t l_start; //锁的起始偏移量off_t l_len;、、被锁定的大小off_t l_pid;...............}fcntl调用结果参数 returnF_DUPFD 新的fdF_GETFD fd标志F_GETFL 文件状态F_GETOWN fd所有者其他参数 0失败 -1eg:#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>int main(int argc,char* argv[]){int fd;int file_stat;if(argc!=2) {printf("usage:%s filename\n",argv[0]); return 1;}fd=open(argv[1],O_RDONLY);if(fd==-1) {perror("cannot open the file\n"); return 1;}file_stat=fcntl(fd,F_GETFL);if(file_stat<0) {perror("cannot get the file status\n"); return 1;}switch(file_stat & O_ACCMODE){case O_RDONLY: printf("file:%s read only\n",argv[0]); break;case O_WRONLY: printf("file:%s write only \n",argv[0]); break;case O_RDWR: printf("file:%s Read and write\n",argv[0]); break;default: printf("unkown access right\n");}return 0;}-----------------------------------使用fcntl实现进程互斥#include <stdio.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>int main(int argc,char* argv[]){int fd,count=0;if(argc!=2){printf("usage:%s lock_file_name",argv[0]);return 1;}struct flock lock;fd=open(argv[1],O_RDWR);if(fd<0) {perror("cannot open the file\n"); return 1;}lock.l_type=F_WRLCK;lock.l_whence=0;lock.l_start=0;while(fcntl(fd,F_SETLK,&lock)<0){switch(errno){case EAGAIN:case EACCES:if(++count<5)sleep(5);else{fcntl(fd,F_GETLK,&lock);printf("pid:%ld process find pid:%ld lock the file %s\n",(long)getpid(),(long)lock.l_pid,argv[1]);return 1;}continue;}perror("function fcntl call fail\n");return 1;}printf("pid:%ld process lock the file\n",(long)getpid());printf("pid:%ld process release the file\n",(long)getpid());return 0;}--------------------------------------------lockf()是fcntl()在文件锁方面的一个简单调用,添加,检测和解除文件锁。head <unistd.h>define int lockf(int fd,int cmd,off_t len);return suc:0 fail:-1 errno:yescmd:F_LOCK F_TLOCK F_ULOCK F_TESTeg:#include <stdio.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>int main(int argc,char* argv[]){int fd,lock_result;struct flock lock;if(argc!=2) {printf("usage:%s lock_file_name\n",argv[0]); return 1;}fd=open(argv[1],O_RDWR);if(fd<0) {perror("cannot open the file\n"); return 1;}lock_result=lockf(fd,F_LOCK,0);if(lock_result==-1) {perror("cannot get the lock\n"); return 0;}printf("pid:%ld process lock the file\n",(long)getpid());printf("pid:%ld process release the file\n",(long)getpid());return 0;}----------------------------flock() 实现对文件的加锁解锁head <sys/file.h>define int flock(int fd,int operation);return suc:0 fail:-1 errno:yesoperation:LOCK_SH:设置共享锁,多个进程可同时对同一文件拥有共享锁LOCK_EX:设置互斥锁LOCK_UN:解除文件锁锁定是不阻塞:LOCK_NB eg:flock(fd,LOCk_EX|LOCK_NB)---------------信号:查看Linux支持的信号:kill -lman 7 signalMan pages are grouped into sections. To see the full list of Linux man pages for a section, pick one of:Section 1 user commands (introduction)Section 2 system calls (introduction)Section 3 library functions (introduction)Section 4 special files (introduction)Section 5 file formats (introduction)Section 6 games (introduction)Section 7 conventions and miscellany (introduction)Section 8 administration and privileged commands (introduction)Section L math library functionsSection N tcl functions 产生信号函数kill() raise() alarm()Namekill - send signal to a processSynopsis#include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);DescriptionThe kill() system call can be used to send any signal to any process group or process.If pid is positive, then signal sig is sent to pid.If pid equals 0, then sig is sent to every process in the process group of the current process.If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init), but see below.If pid is less than -1, then sig is sent to every process in the process group -pid.If sig is 0, then no signal is sent, but error checking is still performed. Return ValueOn success (at least one signal was sent), zero is returned. On error, -1 is returned, and errno is set appropriately.Errors---------------------raise()用于给调用进程自身发送信号head <signal.h>synopsis int raise(int sig);return suc:0 fail:!0 errno:- raise()等同于kill(getpid(),sig)alarm() 定时产生SIGALRM信号header <unistd.h>synopsis unsigned int alarm(unsigned int seconds);return suc:不存在警告时钟返回0,存在,返回上一个警告时钟等待时间 fail:- errno:-eg:#include <stdio.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>int main(){int pid,wait_pid,status,i;for(i=1;i<=5;i++){pid=fork();if(pid<0) {perror("cannot create the new process\n"); return 1;}else if(pid==0){printf("in child process(pid:%ld),the process will terminate in %d seconds\n",(long)getpid(),i);alarm(i);pause();}}while((wait_pid=wait(&status)) && wait_pid!=-1){if(WIFSIGNALED(status)) printf("process id:%d receive SIG:%d exit\n",pid,WTERMSIG(status));if(WIFEXITED(status)) printf("process id:%d exit code %d\n",pid,WEXITSTATUS(status));}return 0;}-----------------------------------进程对信号有3种处理方法:1.系统处理 2.忽略信号 3.捕获信号signal()header <signal.h>synopsis typedef void (*sighandler_t)(int);sighandler_t signal(int signum,sighandler_t handler);return suc:原来的信号处理函数 fail:SIG_ERR errno:yessignum:要捕获的信号值,handler指向要调用的函数指针,可以为SIG_IGN(忽略信号)SIG_DFL(标准信号)也可以是自己的处理函数eg:#include <stdio.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>void sigusr1(int sig){printf("got the SIGUSR1 signal\n");exit(0);}int main(void){if(signal(SIGINT,SIG_IGN)==SIG_ERR){perror("cannot reset the SIGINT signal handler\n");return 1;}if(signal(SIGUSR1,sigusr1)==SIG_ERR){perror("cannot reset the SIGUSR1 signal handler\n");return 1;}pause();return 0;}--------------------./signal后台运行 。对SIGINT忽略,对SIGUSR1信号输出信息,分别用kill -SIGINT 和-SIGUSR1测试结果 用jobs查看结果sigaction() 检查,修改指定信号的处理动作在处理小于SIGRTMIN的信号中 某些unix版本中采用函数处理后恢复成系统处理方式,所以每次处理信号后都要重新设置信号处理函数。这个问题Linux不存在,为了代码的可移植性,采用sigaction()header <signal.h>synopsis int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact);return suc:0 fail:-1 errno:yessignum为要捕获的信号,除了不能捕获的SIGKILL SIGSTOPact:指定动作指针,oldact信号原有处理函数struct sigaction{void (*sa_handler)(int);void (*sa_sigaction)(int,siginfo_t *,void *);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);}sa_mask:用于指定进行信号处理时要屏蔽的信号值,sa_flags用于指定响应信号时的其他行为,取值如下:SA_NOCLDSTOP SA_NOCLDWAIT SA_RESETHAND SA_RESTART SA_NODEFER SA_SIGINFOsa_handler用于指定信号的处理函数,SIG_DFL SIG_IGNsiginfo_t{int si_signo;int si_errno;int si_code;int si_pid;pid_t si_pid;uid_t si_uid;int si_status;clock_t si_utime;clock_t si_stime;sigval_t si_value;int si_int;void * si_ptr;void * si_addr;int si_band;int si_fd;}eg:#include <stdio.h>#include <signal.h>void signal_set(struct sigaction *act){switch(act->sa_flags){case (int)SIG_DFL:printf("using default handler\n");break;case (int)SIG_IGN:printf("ignore the signal\n");break;default: printf("%0x\n",act->sa_handler);}}int main(int argc,char* argv){int i;struct sigaction act,oldact;act.sa_handler=signal_set;act.sa_flags=SA_NODEFER | SA_RESETHAND;sigaction(SIGUSR1,&act,&oldact);for(i=1;i<12;i++){printf("signal %d handler is :",i);sigaction(i,NULL,&oldact);signal_set(&oldact);}return 0;}---------------------------------综合实例:实现对用户邮件的自动检测/var/mail/username 判断该文件大小,守候进程和信号处理模块,lib.base.c#include <unistd.h>#include <sys/types.h>#include <stdio.h>#include <signal.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>int daemon(int nochdir,int noclose){pid_t pid;pid=fork();if(pid<0) {perror("fork\n"); return -1;}if(pid!=0) exit(0);pid=setsid();if(pid<-1) {perror("setpid\n"); return -1;}if(!nochdir) chdir("/");if(!noclose){int fd;fd=open("/dev/null",O_RDWR,0);if(fd!=-1){dup2(fd,STDIN_FILENO);dup2(fd,STDOUT_FILENO);dup2(fd,STDERR_FILENO);if(fd>2) close(fd);}}umask(0027);return 0;}void * signal_set(int signo,void(*func)(int)){int ret;struct sigaction sig,osig;sig.sa_handler=func;sigemptyset(&sig.sa_mask);sig.sa_flags=0;#ifdef SA_RESTARTsig.sa_flags|=SA_RESTART;#endifret=sigaction(signo,&sig,&osig);if(ret<0) return (SIG_ERR);else return (osig.sa_handler);}void sigint(int sig){}void sigtstp(int sig){}void signal_init(){signal_set(SIGINT,sigint);signal_set(SIGTSTP,sigtstp);}----------------------------lib.mail.c#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <stdio.h>#include <signal.h>#include <syslog.h>#define SLEEP_TIME 5long get_file_size(const char* filename){struct stat status;long size;if(stat(filename,&status)==-1) {perror("cannot get the file status\n"); return -1;}size=status.st_size;return size;}void mail_log(const char* progname,const char* mail_pos){fprintf(stderr,"%s notice: you have new mail in %s\n",progname,mail_pos);}int check_mail(const char *filename,const char* progname){long old_mail_size,mail_size;old_mail_size=get_file_size(filename);if(old_mail_size==-1) return 1;if(old_mail_size>0) mail_log(progname,filename);sleep(SLEEP_TIME);while(1){mail_size=get_file_size(filename);if(mail_size!=old_mail_size) mail_log(progname,filename);}old_mail_size=mail_size;sleep(SLEEP_TIME);}-----------------------mail.c#include <stdio.h>#define USER_ACCOUNT "/var/mail/tps"extern void signal_init();extern int daemon(int nochdir,int noclose);int check_mail(const char *filename,const char* progname);int main(int argc,char* argv[]){char *p;int opt,daemon_mode=1;char* progname;signal_init();if(daemon_mode) daemon(0,1);check_mail(USER_ACCOUNT,argv[0]);return 0;}-----------------------------------------------------------------END

http://tunps.com/linux-programming-note-6

原创粉丝点击