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

 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

内容概要:本文详细介绍了如何使用Matlab对地表水源热泵系统进行建模,并采用粒子群算法来优化每小时的制冷量和制热量。首先,文章解释了地表水源热泵的工作原理及其重要性,随后展示了如何设定基本参数并构建热泵机组的基础模型。接着,文章深入探讨了粒子群算法的具体实现步骤,包括参数设置、粒子初始化、适应度评估以及粒子位置和速度的更新规则。为了确保优化的有效性和实用性,文中还讨论了如何处理实际应用中的约束条件,如设备的最大能力和制冷/制热模式之间的互斥关系。此外,作者分享了一些实用技巧,例如引入混合优化方法以加快收敛速度,以及在目标函数中加入额外的惩罚项来减少不必要的模式切换。最终,通过对优化结果的可视化分析,验证了所提出的方法能够显著降低能耗并提高系统的运行效率。 适用人群:从事暖通空调系统设计、优化及相关领域的工程师和技术人员,尤其是那些希望深入了解地表水源热泵系统特性和优化方法的专业人士。 使用场景及目标:适用于需要对地表水源热泵系统进行精确建模和优化的情景,旨在找到既满足建筑负荷需求又能使机组运行在最高效率点的制冷/制热量组合。主要目标是在保证室内舒适度的前提下,最大限度地节约能源并延长设备使用寿命。 其他说明:文中提供的Matlab代码片段可以帮助读者更好地理解和复现整个建模和优化过程。同时,作者强调了在实际工程项目中灵活调整相关参数的重要性,以便获得更好的优化效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值