热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

.linux进程知识程序存储、crontab、fork与vfork、exec、_exit()、wait()与waitpid()、孤儿和僵尸文件读写文件锁、select、poll

.linux进程知识程序存储、crontab、fork与vfork、exec、_exit()、wait()与waitpid()、孤儿和僵尸文件读写文件锁、select、poll分类:linu
 

.linux进程知识 程序存储、crontab、fork与vfork、exec、_exit()、wait()与waitpid()、孤儿和僵尸 文件读写 文件锁、select、poll

分类: linux 312人阅读 评论(0) 收藏 举报 LinuxC网络

目录(?)[+]

一、程序存储

      经常被问到进程与线程的区别,今天有人问程序与进程的区别,一下子还真没反应过来 敲打  。程序只是一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体。而进程则不同,它是程序在某个数据集上的执行。进程是一个动态的实体,它有自己的生命周期。反映了一个程序在一定的数据集上运行的全部动态过程。 

 

 

二、crontab

 

基本格式 :
*  *  *  *  *  command
分 时 日 月 周 命令

第1列表示分钟1~59 每分钟用*或者 */1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令

 

在终端输入:crontab -e

然后编辑内容为:* * 9 10 0 echo "now the time is .... `date` " >>/home/fsy/io/tempfile

查看:crontab -l

删除:crontab -r

 

 

三、关于fork 进程的补充

   1、用重定向方式输出时应该注意:调用fork的程序,会完全复制一个父进程。所以也会复制一个缓冲区,及如果父进程在缓冲区中有内容,则子进程也会一并获得。那为什么对文件的读写不是两个文件呢?因为子进程复制的是文件标示符,转成文件指针会指向同一个文件。

 

    2、fork用于父子进程同时指行不同的代码段,比如网络服务进程。或用于要执行一个不同的程序,通常是子进程从fork返回后立即调用exec。

 

    3、vfrok()不复制父进程的地址空间。子进程一定是先运行。在调用exec/exit之前,它在父进程的空间中运行

 

四、exec族

  函数还真多,就是功能都一样。一大家子人,长的还差不多,只能干一样事。这存在感,真服了敲打

 

 

 个人感觉记住一个就行:execlp("ls","ls","-l",NULL);

 

 错误判断:

errno=ENOENT    找不到文件或路径

errno=EFAULT     argv/envp忘记用NULL结束

errno=EACCES    没有运行权限

 

 

五、exit()与_exit()

 

    最好使用exit()退出程序。因为会清空缓存。exit()在中。_exit()在中。中间的参数,可以用wait系统调用接收子进程返回值。

 

六、wait与waitpid()

 

  wait()使父进程阻塞直到子进程结束才返回。wait()是waitpid()的一个特例。所以waitpid()更牛一些~

    

 

    通常说来waitpid(),用于等待一个特定的子进程。调用方法为:waitpid(pid1, &stu, WNOHANG) 或者 waitpid(pid1, NULL, 0)微笑

 

 

七、孤儿与僵尸(进程)

   这个...不知道是作者有才,还是翻译有思想,弄出了这么俩词 尴尬 

 

     父进程先死了,子进程就是孤儿了。但是别担心,咱是和 *谐社会,怎么能有孤儿呢?所以马上有个大爹——init 收养这些没人要的进程。

 

    要是子进程先死了,父进程没回收子进程,那他就成了孤魂野鬼。也就变僵尸了惊恐  所以父进程要收尸啊...... 这个也好解决。收尸其实也不费劲,调用wait()/waitpid()就行。这个到处都是僵尸,对社会的安定团结还是有很大影响的。系统所能使用的进程号是有限的,子进程不回收,虽然不占内存了,但是进程号还占着,僵尸多了,正常的子进程就没有进程号了......

 

 

 

一、进程组与会话

    进程组:是一个或多个进程的集合。可以调用 getpgid(0) 或 getpgrp() 来得到。进程组ID为组长的进程ID。只要进程组中有一个进程存在,进程组就存在,与组长进程是否终止无关。调用 setpgid() 加入一个现有的进程组或创建一个新的进程组。

 

    会话:一个或多个进程组的集合

 

 

       可以用 setsid() 建立新会话,则该进程会变成新会话的首进程,同时成为一个新进程组的组长进程,该进程没有控制终端

 

二、守护进程

    守护进程的特点:没有终端的限制,不受用户、终端或其它的变化而受到影响。

   

 创建守护进程的步骤:

 

    出错处理:因为守护进程不依赖于终端,所以出错信息是不能用 printf 滴,这..... 怎么办?莫怕,用 syslog() 就能搞定~

 

     用系统日志就要调用三个函数:openlog()、syslog()、closelog()  系统日志存于 /var/log/messages

 

举例:

[cpp] view plaincopyprint?
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5.   
  6. int main(){  
  7.     pid_t pid,s;  
  8.     int i;  
  9.     char *buff="Daemon Test!\n";  
  10.     if((pid = fork())<0){  
  11.         printf("fork error!\n");  
  12.         exit(1);  
  13.     }else if(pid> 0){  
  14.         exit(0);  
  15.     }  
  16.       
  17.     //第一个参数为在消息之前加入的字符串,第二个参数在每个消息中包含进程的ID,第三个参数指定程序发送的消息类型   
  18.     openlog("daemon_testlog",LOG_PID,LOG_DAEMON);     
  19.     if((s=setsid())<0){  
  20.         //第一个参数为参数类型,第二个参数为信息字符串   
  21.         syslog(LOG_ERR,"%s\n","setsid error!");     
  22.     }  
  23.     chdir("/");  
  24.     umask(0);  
  25.     for(i=0;i//关闭文件描述   
  26.         close(i);  
  27.     }  
  28.     while(1){  
  29.         syslog(LOG_INFO,"%s\n",buff);  
  30.         sleep(10);  
  31.     }  
  32.     closelog();  
  33.     return 0;  
  34. }  
[cpp] view plaincopyprint?
  1. #include  
  2. #include  
  3. #include  
  4. #include  
  5.   
  6. int main(){  
  7.     pid_t pid,s;  
  8.     int i;  
  9.     char *buff="Daemon Test!\n";  
  10.     if((pid = fork())<0){  
  11.         printf("fork error!\n");  
  12.         exit(1);  
  13.     }else if(pid> 0){  
  14.         exit(0);  
  15.     }  
  16.       
  17.     //第一个参数为在消息之前加入的字符串,第二个参数在每个消息中包含进程的ID,第三个参数指定程序发送的消息类型  
  18.     openlog("daemon_testlog",LOG_PID,LOG_DAEMON);     
  19.     if((s=setsid())<0){  
  20.         //第一个参数为参数类型,第二个参数为信息字符串  
  21.         syslog(LOG_ERR,"%s\n","setsid error!");     
  22.     }  
  23.     chdir("/");  
  24.     umask(0);  
  25.     for(i=0;i//关闭文件描述  
  26.         close(i);  
  27.     }  
  28.     while(1){  
  29.         syslog(LOG_INFO,"%s\n",buff);  
  30.         sleep(10);  
  31.     }  
  32.     closelog();  
  33.     return 0;  
  34. }  

 

 

三、信号

 

    Linux对每种信号都制定了默认的操作。捕捉到信号可以采用默认的操作、可以忽略(SIGKILL 与 SIGSTOP除外)、也可以执行相应的自定义处理函数。

 

kill()、raise() 发信号。一些相关知识可以参考 Linux 信号通信  

pause() 将进程挂起直到捕捉到信号为止。

 

举例1:

[cpp] view plaincopyprint?
  1. #include    
  2. #include    
  3. #include    
  4.   
  5. void my_func(int);  
  6.   
  7. int main() {  
  8.     printf("Wainting for signal: SIGINT/SIGQUIT...\n");  
  9.     signal(SIGINT,my_func);  
  10.     signal(SIGQUIT,my_func);  
  11.     pause();  
  12.     pause();  
  13.     exit(0);  
  14. }  
  15.   
  16. void my_func(int sign_no){  
  17.     if (sign_no==SIGINT) {  
  18.         printf("I got CTRL+C!\n");  
  19.     } else if (sign_no==SIGQUIT) {  
  20.         printf("I got CTRL+\\!\n");  
  21.     }   
  22. }  
[cpp] view plaincopyprint?
  1. #include   
  2. #include   
  3. #include   
  4.   
  5. void my_func(int);  
  6.   
  7. int main() {  
  8.     printf("Wainting for signal: SIGINT/SIGQUIT...\n");  
  9.     signal(SIGINT,my_func);  
  10.     signal(SIGQUIT,my_func);  
  11.     pause();  
  12.     pause();  
  13.     exit(0);  
  14. }  
  15.   
  16. void my_func(int sign_no){  
  17.     if (sign_no==SIGINT) {  
  18.         printf("I got CTRL+C!\n");  
  19.     } else if (sign_no==SIGQUIT) {  
  20.         printf("I got CTRL+\\!\n");  
  21.     }   
  22. }  

举例2: 

[cpp] view plaincopyprint?
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5.   
  6. int main(){  
  7.     pid_t pid;  
  8.     if((pid = fork())<0){  
  9.         printf("fork error!\n");  
  10.         exit(1);  
  11.     }else if(pid == 0){  
  12.         printf("Child process wait for singal....a\n");  
  13.         raise(SIGSTOP);     //子进程向自己发送一个消息,线程停止   
  14.         printf("Child is dead\n");    //此句不会打出来,因为进程直接被kill了   
  15.     }else{  
  16.         sleep(10);  
  17.         kill(pid,SIGKILL);  
  18.         wait(NULL);  
  19.     }  
  20.     return 0;  
  21. }  
[cpp] view plaincopyprint?
  1. #include  
  2. #include  
  3. #include  
  4. #include  
  5.   
  6. int main(){  
  7.     pid_t pid;  
  8.     if((pid = fork())<0){  
  9.         printf("fork error!\n");  
  10.         exit(1);  
  11.     }else if(pid == 0){  
  12.         printf("Child process wait for singal....a\n");  
  13.         raise(SIGSTOP);     //子进程向自己发送一个消息,线程停止  
  14.         printf("Child is dead\n");    //此句不会打出来,因为进程直接被kill了  
  15.     }else{  
  16.         sleep(10);  
  17.         kill(pid,SIGKILL);  
  18.         wait(NULL);  
  19.     }  
  20.     return 0;  
  21. }  

 

   alarm()  在进程中设置一个定时器,当时间到时,发出SIGALARM信号。一个进程只能有一个闹钟时间,新的将代替旧的。返回值为新旧时间差值。

 

举例:

[cpp] view plaincopyprint?
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5.   
  6. int main(){  
  7.     int ret=alarm(5);  
  8.     printf("alarm...%d\n",ret);  
  9.     sleep(3);  
  10.     ret=alarm(5);  
  11.   
  12.     printf("alarm...%d\n",ret);  
  13.     pause();  
  14.     printf("never show\n");  
  15.   
  16. }  
[cpp] view plaincopyprint?
  1. #include  
  2. #include  
  3. #include  
  4. #include  
  5.   
  6. int main(){  
  7.     int ret=alarm(5);  
  8.     printf("alarm...%d\n",ret);  
  9.     sleep(3);  
  10.     ret=alarm(5);  
  11.   
  12.     printf("alarm...%d\n",ret);  
  13.     pause();  
  14.     printf("never show\n");  
  15.   
  16. }  


程序运行结果为:alarm...0    alarm....2  。 2为相差时间,程序收到SIGALARM默认执行的操作为终止线程。

 

sigaction()函数:signal()的高级版~

 

例子:

[cpp] view plaincopyprint?
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5.   
  6. void my_func(int);  
  7.   
  8.   
  9. int main(){  
  10.     struct sigaction sa,oldsa;  
  11.   
  12.     printf("waiting for SIGINT/SIGQUIT......\n");  
  13.     sa.sa_handler=my_func;         //设定处理函数   
  14.     sigemptyset(&sa.sa_mask);      //清空信号集合   
  15.     sa.sa_flags=0;                //对信号处理的选项一般设为0   
  16.   
  17.     sigaction(SIGINT,&sa,&oldsa);     //oldsa为保存旧的信号结构体   
  18.     sigaction(SIGQUIT,&sa,&oldsa);  
  19.   
  20.     pause();  
  21.     pause();  
  22.     pause();  
  23.     pause();  
  24.     pause();  
  25.     pause();  
  26.     pause();  
  27.   
  28. }  
  29.   
  30. void my_func(int sig){  
  31.     if(sig == SIGINT){  
  32.         printf("Receive CTRL+C!\n");  
  33.     }  
  34.     else if(sig == SIGQUIT){  
  35.         printf("Receive CTRL+\\!\n");  
  36.     }else  
  37.     printf("Receive Signal!\n");  
  38. }  
[cpp] view plaincopyprint?
  1. #include  
  2. #include  
  3. #include  
  4. #include  
  5.   
  6. void my_func(int);  
  7.   
  8.   
  9. int main(){  
  10.     struct sigaction sa,oldsa;  
  11.   
  12.     printf("waiting for SIGINT/SIGQUIT......\n");  
  13.     sa.sa_handler=my_func;         //设定处理函数  
  14.     sigemptyset(&sa.sa_mask);      //清空信号集合  
  15.     sa.sa_flags=0;                //对信号处理的选项一般设为0  
  16.   
  17.     sigaction(SIGINT,&sa,&oldsa);     //oldsa为保存旧的信号结构体  
  18.     sigaction(SIGQUIT,&sa,&oldsa);  
  19.   
  20.     pause();  
  21.     pause();  
  22.     pause();  
  23.     pause();  
  24.     pause();  
  25.     pause();  
  26.     pause();  
  27.   
  28. }  
  29.   
  30. void my_func(int sig){  
  31.     if(sig == SIGINT){  
  32.         printf("Receive CTRL+C!\n");  
  33.     }  
  34.     else if(sig == SIGQUIT){  
  35.         printf("Receive CTRL+\\!\n");  
  36.     }else  
  37.     printf("Receive Signal!\n");  
  38. }  


信号集

 

 

  通常就是这个步骤。清空信号集->添加信号->设置信号屏蔽->定义信号处理

 

举例:

[cpp] view plaincopyprint?
  1. #include    
  2. #include    
  3. #include    
  4. #include    
  5. #include    
  6.   
  7. void my_func(int);  
  8.   
  9. int main() {  
  10.     struct sigaction sa1,sa2;  
  11.     sigset_t set;  
  12.     //清空   
  13.     if (sigemptyset(&set)<0) {  
  14. var cpro_id = "u6885494";
推荐阅读
  • 在尝试加载支持推送通知的iOS应用程序的Ad Hoc构建时,遇到了‘no valid aps-environment entitlement found for application’的错误提示。本文将探讨此错误的原因及多种可能的解决方案。 ... [详细]
  • 本文详细介绍了 `org.apache.tinkerpop.gremlin.structure.VertexProperty` 类中的 `key()` 方法,并提供了多个实际应用的代码示例。通过这些示例,读者可以更好地理解该方法在图数据库操作中的具体用途。 ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • spring boot使用jetty无法启动 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 长期从事ABAP开发工作的专业人士,在面对行业新趋势时,往往需要重新审视自己的发展方向。本文探讨了几位资深专家对ABAP未来走向的看法,以及开发者应如何调整技能以适应新的技术环境。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 如何从BAM文件绘制ATAC-seq插入片段长度分布图?
    在ATAC-seq数据处理中,插入片段长度的分布图是一个重要的质量控制指标,它能反映出核小体的周期性排列。本文将详细介绍如何从BAM文件中提取并绘制这些数据。 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 本文将从基础概念入手,详细探讨SpringMVC框架中DispatcherServlet如何通过HandlerMapping进行请求分发,以及其背后的源码实现细节。 ... [详细]
  • 高级缩放示例.就像谷歌地图一样.它仅缩放图块,但不缩放整个图像.因此,缩放的瓷砖占据了恒定的记忆,并且不会为大型缩放图像调整大小的图像.对于简化的缩放示例lookhere.在Win ... [详细]
  • 小编给大家分享一下Vue3中如何提高开发效率,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获, ... [详细]
  • 本文详细介绍了Elasticsearch中的分页查询机制,包括基本的分页查询流程、'from-size'浅分页与'scroll'深分页的区别及应用场景,以及两者在性能上的对比。 ... [详细]
author-avatar
ayo
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有