C/C++进程超详细详解【中部分】(系统性学习day07) 太过爱你忘了你带给我的痛 2024-02-27 05:43 28阅读 0赞 ## ## **目录** 前言 一、守护进程 1.概念 2.守护进程创建的原理(如图清晰可见) 3.守护进程的实现(代码块) 二、dup和dup2 1,复制文件描述符 2.文件描述符重定向 三、系统日志 1,打开日志 2,向日志中写消息 3,关闭日志 四,文件锁 1.概念 2,给整个文件上锁 实例代码如下: 3,给文件的某个区域上锁 实例代码如下: 五,进程间通信 1.分类 2,无名管道 2.1 无名管道通信原理 2.2 用法 实例代码如下: 总结 -------------------- ## 前言 ## 上篇博客对C/C++进程的上部分进行了详细讲解,本篇博客将继续讲解和补充关于线程的知识点。 -------------------- ## 一、守护进程 ## ### 1.概念 ### > (1)守护进程, > 也就是通常所说的Daemon进程,是Linux中的后台服务进程。 > 它是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件 > 守护进程常常在系统引导装入时启动,在系统关闭时终止 > Linux系统有很多守护进程,大多数服务都是用守护进程实现的 > > (2)终端 > 在Linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会被自动关闭。 > > 守护进程能够突破这种限制,它从被执行开始运转,直到整个系统关闭才会退出。 > 如果想让某个进程不因为用户或终端或其他的变化而受到影响,就必须把这个进程变成一个守护进程。 ### 2.守护进程创建的原理(如图清晰可见) ### ![f4f859cd21dc4e8f8f5a47fc66483ca8.png][] ### 3.守护进程的实现(代码块) ### void init_deamon(void) { /*************** start ****************************/ pid_t pid; int i,max_fd; //1,创建子进程 if((pid = fork()) < 0){ perror("fork"); exit(1); }else if(pid > 0) exit(0); //2,创建新会话 if(setsid() < 0){ perror("setsid"); exit(1); } //3,再创建子进程 if((pid = fork()) < 0){ perror("fork"); exit(1); }else if(pid > 0) exit(0); //4,修改守护进程的工作目录 chdir("/"); //5,关闭进程父进程的所有的文件描述符 max_fd = sysconf(_SC_OPEN_MAX); for (i = 0; i < max_fd;i++) close(i); //6,将标准输入,标准输出和标准错误重定向到/dev/null open("/dev/null",O_RDWR); dup(0); dup(0); //7,消除umask影响 umask(0); /*************** end ****************************/ } ## 二、dup和dup2 ## ### 1,复制文件描述符 ### > int dup(int oldfd); > //参数 ---- 要复制的文件描述符 > //返回值 ----成功:新的文件描述符,失败:-1 > > 例如: > int main(void) > \{ > char str\[\] = "hello world"; > int fd1,fd2; > > > fd1 = open("1.txt",O\_RDWR|O\_CREAT,0666); > if(fd1 < 0)\{ > perror("open"); > exit(1); > \} > > write(fd1,str,strlen(str)); > > fd2 = dup(fd1); //复制文件描述fd1 > strcpy(str,"farsight"); > write(fd2,str,strlen(str)); > > close(fd1); > > > return 0; > \} > ### 2.文件描述符重定向 ### > int dup2(int oldfd, int newfd); > //参数1 --- 目标文件描述符 > //参数2 --- 要重定向的文件描述符 > //返回值 ---- 成功0,失败:-1 > > 例如: > int main(void) > \{ > char str\[\] = "hello world"; > int fd1,fd2; > > > fd1 = open("1.txt",O\_RDWR|O\_CREAT,0666); > if(fd1 < 0)\{ > perror("open"); > exit(1); > \} > fd2 = open("2.txt",O\_RDWR|O\_CREAT,0666); > if(fd1 < 0)\{ > perror("open"); > exit(1); > \} > > write(fd1,str,strlen(str)); > > dup2(fd1,fd2); //将fd2重定向到fd1 > > strcpy(str,"farsight"); > write(fd2,str,strlen(str)); > close(fd1); > > > return 0; > \} ## 三、系统日志 ## ### 1,打开日志 ### > \#include <syslog.h> > void openlog(const char \*ident, int option, int facility); > //参数1 ------ //日志标签,自定义,方便查找日志信息 > //参数2 ------ 选项: > LOG\_CONS 如果消息不能发送给日志,则发送到控制台 > LOG\_NDELAY 不延迟打开套接字,并发送消息 > LOG\_NOWAIT 创建子进程,不阻塞发送消息给日志 > LOG\_PERROR 发送日志,同时发送到标准错误文件 > LOG\_PID 在消息中加入进程的ID > //参数3 ------ 进程类型: > LOG\_DAEMON 守护进程 > LOG\_FTP tfp服务进程 > LOG\_KERN 内核进程 > LOG\_LPR 打印服务进程 > LOG\_MAIL 邮件服务进程 > 实例如下: > openlog("mydaemon",LOG\_PID,LOG\_DAEMON); ### 2,向日志中写消息 ### > void syslog(int priority, const char \*format, ...); > //参数1 ----- 消息的优先级 > LOG\_EMERG 非常紧急的错误 > LOG\_ALERT 必须马上处理的错误 > LOG\_CRIT 关键性错误 > LOG\_ERR 一般错误 > LOG\_WARNING 警告 > LOG\_NOTICE 需要注意的消息 > LOG\_INFO 正常消息 > LOG\_DEBUG 调试消息 > //参数2 -----向日志中写消息的格式 > //变参 ----- 类似于printf的变参 > 例如: > syslog(LOG\_ERR,"fopen:%s",strerror(errno)); > > 运行测试: > grep mydaemon /var/log/syslog -n > 203:Sep 26 23:36:26 ubuntu mydaemon\[28968\]: fopen:No such file or directory ### 3,关闭日志 ### > void closelog(void); ## 四,文件锁 ## ### 1.概念 ### > 为了解决进程之间的互斥问题,引入咨询锁 > > 采用锁文件的方式取代创建文件的方式 > 需遵循“君子协定” > 共享锁(shared Lock)和互斥锁(exculusive lock) > 对整个文件上锁或者文件的某个部分上锁(记录锁定) ### 2,给整个文件上锁 ### > \#include <sys/file.h> > int flock(int fd, int operation); > //参数1 ---- 文件描述符 > //参数2 ---- 锁的类型:LOCK\_SH LOCK\_EX LOCK\_UN > //返回值 ---成功:0,失败:-1 #### 实例代码如下: #### 代码一: int main(int argc,char **argv) { int fd; int i; if(argc != 2){ fprintf(stderr,"Usage: %s <filename>\n",argv[0]); exit(0); } if((fd = open(argv[1],O_RDWR)) < 0){ perror("open"); exit(1); } while(1){ printf("等待获取锁\n"); //获取互斥锁 if(flock(fd,LOCK_EX) < 0){ perror("flock"); exit(1); } for(i = 0; i < 7; i++){ printf("正在上厕所\n"); sleep(1); } //释放锁 if(flock(fd,LOCK_UN) < 0){ perror("flock"); exit(1); } printf("上完厕所出来了....\n"); sleep(1); } return 0; } 代码二: int main(int argc,char **argv) { int fd; int i; if(argc != 2){ fprintf(stderr,"Usage: %s <filename>\n",argv[0]); exit(0); } if((fd = open(argv[1],O_RDWR)) < 0){ perror("open"); exit(1); } while(1){ printf("等待着上厕所\n"); //获取互斥锁 if(flock(fd,LOCK_EX) < 0){ perror("flock"); exit(1); } for(i = 0; i < 7; i++){ printf("正在上厕所...\n"); sleep(1); } //释放锁 if(flock(fd,LOCK_UN) < 0){ perror("flock"); exit(1); } printf("上完厕所!\n"); sleep(1); } return 0; } ### 3,给文件的某个区域上锁 ### > \#include <unistd.h> > \#include <fcntl.h> > int fcntl(int fd, int cmd, ... /\* arg \*/ ); > > struct flock \{ > short l\_type; /\* Type of lock: F\_RDLCK, F\_WRLCK, F\_UNLCK \*/ > short l\_whence; /\* How to interpret l\_start: > SEEK\_SET, SEEK\_CUR, SEEK\_END \*/ > off\_t l\_start; /\* Starting offset for lock \*/ > off\_t l\_len; /\* Number of bytes to lock \*/ > pid\_t l\_pid; /\* PID of process blocking our lock > (set by F\_GETLK and F\_OFD\_GETLK) \*/ > \}; #### 实例代码如下: #### //定义锁的结构体--设置锁的区域 struct flock fl = { .l_whence = SEEK_SET, .l_start = 100, .l_len = 1024, }; while(1){ printf("等待获取锁\n"); //获取互斥锁 fl.l_type = F_WRLCK; //设置锁的类型 if(fcntl(fd,F_SETLKW,&fl) < 0){ perror("flock"); exit(1); } for(i = 0; i < 7; i++){ printf("正在上厕所\n"); sleep(1); } //释放锁 fl.l_type = F_UNLCK; //解锁 if(fcntl(fd,F_SETLK,&fl) < 0){ perror("flock"); exit(1); } printf("上完厕所出来了....\n"); sleep(1); } ## 五,进程间通信 ## ### 1.分类 ### > 在linux中进程间通信分为三类: > (1)早期的进程间通信 > 无名管道 > 有名(命名)管道 > 信号 > (2)system V IPC > 消息队列 > 共享内存 > 信号灯(量) > (3)unix域套接字 ### 2,无名管道 ### #### 2.1 无名管道通信原理 #### ![3a7d0a49524941f0ab784fa3dd6455a9.png][] #### 2.2 用法 #### > \#include <unistd.h> > int pipe(int pipefd\[2\]); > //参数 ---- 保存管道两端文件描述符的数组 > //返回值 ---成功:0,失败:-1 ##### 实例代码如下: ##### int main(void) { int fd[2]; pid_t pid; char buf[100]; //创建无名管道 if(pipe(fd) < 0){ //pipe()会在内核中创建无名管道,然后将管道两端的文件描述符返回给当前进程 perror("pipe"); exit(1); } //创建子进程 if((pid = fork()) < 0){ perror("fork"); exit(1); }else if(!pid){ //子进程执行:从键盘获取字符串,写到管道中 close(fd[0]); //关闭读端 while(1){ fgets(buf,sizeof(buf),stdin); write(fd[1],buf,strlen(buf)); //向管道中写数据 } }else{ //父进程执行:从管道读数据,打印到屏幕上 close(fd[1]); //关闭写端 while(1){ if(read(fd[0],buf,sizeof(buf)) < 0){ perror("read"); exit(1); } printf("%s",buf); } } return 0; } ### ### -------------------- ## 总结 ## 本篇文章针对进程进行超详细讲解和补充,希望能够帮到大家! 以后还会给大家展现更多关于嵌入式和C语言的其他重要的基础知识,感谢大家支持懒大王! 希望这篇博客能给各位朋友们带来帮助,最后懒大王请来过的朋友们留下你们宝贵的三连以及关注,感谢你们! [f4f859cd21dc4e8f8f5a47fc66483ca8.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/02/27/b9218fe153a8442d8d400f592243af21.png [3a7d0a49524941f0ab784fa3dd6455a9.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/02/27/41c223bfce774d0795e9eaf50c79fe78.png
相关 进程以及进程调度(超详细) 目录 一 进程 1.1 进程的定义 1.2 电脑中的进程 二 进程与程序的区别和联系 2.1 进程与程序的实例 2.2 进程与程序的区别 2.3 进程与程序的联系 怼烎@/ 2024年03月25日 22:55/ 0 赞/ 58 阅读
相关 初识C语言——详细入门(系统性学习day4) 目录 前言 一、C语言简单介绍、特点、基本构成 简单介绍: 特点: 基本构成: 二、认识C语言程序 标准格式: 简单C程序: 三、基本构成分类详细介绍 ( 小鱼儿/ 2024年03月02日 04:22/ 0 赞/ 19 阅读
相关 C/C++进程超详细详解【中部分】(系统性学习day07) 目录 前言 一、守护进程 1.概念 2.守护进程创建的原理(如图清晰可见) 3.守护进程的实现(代码块) 二、dup和dup2 1,复制文件描述符 2 太过爱你忘了你带给我的痛/ 2024年02月27日 05:43/ 0 赞/ 29 阅读
相关 C/C++ 进程间通信system V IPC对象超详细讲解(系统性学习day9) 目录 前言 一、system V IPC对象图解 1.流程图解: 编辑 2.查看linux内核中的ipc对象: 二、消息队列 1.消息队列的原理 2. 谁借莪1个温暖的怀抱¢/ 2024年02月24日 02:12/ 0 赞/ 22 阅读
相关 C/C++ 线程超详细讲解(系统性学习day10) 目录 前言 一、线程基础 1.概念 2.一个进程中多个线程特征 2.1 线程共有资源 2.2 线程私有资源 3.线程相关的api函数 3.1 创建 桃扇骨/ 2024年02月23日 01:22/ 0 赞/ 25 阅读
相关 CCS6.2超详细使用方法 CCS6.2超详细使用方法 本文介绍了如何安装CCS6.2、一步一步的建立工程、以及建立工程以后编译、调试、如何方便快捷有效率的使用CCS6.2。 一、 忘是亡心i/ 2022年07月14日 06:42/ 0 赞/ 200 阅读
相关 python学习——day07 本文参与「少数派读书笔记征文活动」[https://sspai.com/post/45653][https_sspai.com_post_45653] 参考文章:[http: 迈不过友情╰/ 2022年05月18日 02:52/ 0 赞/ 353 阅读
相关 Java学习 day07 ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0JsZXNz 爱被打了一巴掌/ 2021年11月17日 06:44/ 0 赞/ 256 阅读
相关 Java基础学习Day07 知识点 1. 重写(override) 2. 多态 重写(override) 1. 子类继承父类时 2. 方法名 参数列表一致 3. 修饰符不能被缩小范 怼烎@/ 2021年11月04日 12:28/ 1 赞/ 389 阅读
还没有评论,来说两句吧...