文章目录

  • 进程
    • 程序和进程
    • 产生进程
    • 销毁进程
    • 多进程高并发设计
    • 孤儿僵尸守护进程
      • 孤儿进程:
      • 守护进程(重点)
    • 僵尸进程:

进程

程序和进程

操作系统可以运行多个程序,那他是如何运行的?实际上,CPU的执行是很快的,而待运行的程序很多,那么为了让操作系统运行多个程序,CPU会把它的执行时间划分成很多段,比如每一段是0.1秒,那么就可以这样A程序运行0.1秒,然后B程序运行0.1,然后C程序运行0.2秒,因为这个切换很快,所以我们感觉程序是同时运行的。

产生进程

  • 创建进程很简单,直接调用fork函数:pid_t fork(void);

创建进程用法举例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(){int pid = 0;// 父子进程不共享局部变量// pid_t fork(void);pid_t fpid = fork(); // fpid表示fork函数返回的值if(fpid < 0){printf("创建子进程失败\n");return fpid;}else if(fpid == 0){// 创建成功后子进程中fpid == 0pid = getpid();printf("子进程,子进程pid = %d\n",getpid());}else if(fpid > 0){// 创建成功后父进程的fpid 为子进程的pidpid = getpid();printf("父进程,父进程pid = %d\n",getpid());printf("父进程,子进程pid = %d\n",getpid());}// 再创建3个子进程用于观察for(int i = 3 ; i > 0 && fpid > 0 ; i--){fpid = fork();}printf("pid = %d\n",pid);while (1);return 0;
}

调用fork函数后,会创建一个子进程,并且父子两个进程都从fork处执行,fork函数有两个返回值,对于父进程会返回子进程的pid,此时pid会大于0,对于子进程来说,pid会等于0。

局部变量:写时复制,读时共享

销毁进程

exit - 终止正在执行的进程

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main()
{int pid = 0;// pid_t fork(void);pid_t fpid = fork();if (fpid < 0){printf("创建子进程失败\n");return fpid;}else if (fpid == 0){printf("我是子进程,马上就要exit了\n");exit(-1);printf("子进程还活着\n");}else if (fpid > 0){printf("父进程还活着\n");}while (1);return 0;
}

这里子进程已经退出,但是父进程没有执行完毕,导致子进程没有回收变成僵尸进程

多进程高并发设计


优点:

  • 若要用多进程实现高并发那么自己linxu系统cpu有多少核,就产生多少个进程多个核可以并发执行只有多个进程在不同的核上运行才可以充分利用多核系统的并发处理能力

  • 比如:cpu为四核,那么主进程就产生4个子进程,让四个子进程分别在不同的核上运行,

  • 4个子进程在工作的时候,把任务放在一个共享内存中(通过内存映射,使多个进程可以访问一个内存),哪个任务做完了,就接着拿任务给每个子进程的负载均衡

  • 职责明确:父进程管理生死,子进程工作

查看cpu核数

cat /proc/cpuinfo
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);int main(int argc, char **argv)
{// 子进程用于工作,父进程用于管理子进程// 开启工作进程,创建4个子进程start_worker_processes(4);// 管理子进程wait(NULL);
}// 开启工作进程
void start_worker_processes(int n)
{int i = 0;for (i = n - 1; i >= 0; i--){// 创建子进程spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");}
}// 创建子进程
// spawn_proc_pt 类型的函数:void worker_process_cycle(void *data)
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{pid_t pid;pid = fork(); // 创建子进程switch (pid){case -1:fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);return -1;case 0:proc(data); // 成功创建子进程后让子进程去工作return 0;default:break;}printf("start %s %ld\n", name, (long int)pid);return pid;
}// 给进程安排工作
void worker_process_cycle(void *data)
{// data 其实是一个int*类型int worker = (intptr_t)data;// 初始化worker_process_init(worker);// 干活for (;;){sleep(10);printf("pid %ld ,doing ...\n", (long int)getpid());}
}// 初始化进程
void worker_process_init(int worker)
{cpu_set_t cpu_affinity;// worker = 2;// 多核高并发处理  4core  0 - 0 core 1 - 1  2 -2 3 -3CPU_ZERO(&cpu_affinity); // 结构体清零// CPU_SETSIZE:1024 支持cpu最大的数量CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3 设置核/*在多CPU系统中,通过sched_setaffinity ()可以设置进程的CPU亲和力,使进程绑定在某一个或几个CPU上运行,避免在CPU之间来回切换,从而提高该进程的实时性能。*/if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1){fprintf(stderr, "sched_setaffinity() failed\n");}
}

查看进程对应的核数

代码中函数指针不太理解的看看下方代码:

// typedef  返回类型(*新类型)(参数表)
typedef char (*PTRFUN)(int);
PTRFUN pFun;
char glFun(int a){ return;}
void main()
{ pFun = glFun; (*pFun)(2);  //调用函数
}

查看进程在cpu的核上执行的命令: ps -eLo ruser,pid,lwp,psr,args

孤儿僵尸守护进程

孤儿进程:

一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
想想我们如何模仿一个孤儿进程? 答案是: kill 父进程!

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(){int fpid = 1;// 父子进程不共享局部变量for(int i = 5 ; i > 0 && fpid > 0 ; i--){fpid = fork();}if(fpid < 0){printf("创建子进程失败\n");return fpid;}else if(fpid == 0){while(1);}else if(fpid > 0){while(1);}return 0;
}

守护进程(重点)

把孤儿进程做成守护进程

不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务。守护进程脱离于终端,是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端所产生的终端信息所打断(比如关闭终端等)。那如何成为一个守护进程呢? 步骤如下:

  • 1.调用fork(),创建新进程,它会是将来的守护进程.
  • 2.在父进程中调用exit(父进程挂掉),保证子进程不是进程组长
  • 3.调用setsid()创建新的会话区 – 具体先不追究
  • 4.将当前目录改成根目录(如果把当前目录作为守护进程的目录,当前目录不能被卸载他作为守护进程的工作目录)
  • 5.将标准输入,标准输出,标准错误重定向到/dev/null.
    我们来看这个代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>// 一般传入 0 , 0
int daemon(int nochdir, int noclose)
{int fd = 0;switch (fork()){case -1:return (-1);case 0:break;default:_exit(0); // 父进程自杀}if (setsid() == -1) // 创建会画return (-1);if (!nochdir) // 将当前目录改成根目录(void)chdir("/");if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1){// 重定向 标准输入 标准输出 标准出错(void)dup2(fd, STDIN_FILENO);(void)dup2(fd, STDOUT_FILENO);(void)dup2(fd, STDERR_FILENO);if (fd > 2)(void)close(fd);}return (0);
}int main()
{// 创建子进程,并且把父进程杀死daemon(0,0);printf("hello\n");while(1);// 处理事务return 0;
}

父进程自杀后,守护进程 init 接管 , 一直在后台进行运行

僵尸进程:

一个进程使用fork创建子进程,如果子进程退出(exit),而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

  1. 僵尸进程怎样产生的:
  • 一个进程使用fork创建子进程,如果子进程退出(exit),而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
  • 它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了, 那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。

1.怎么查看僵尸进程:
  利用命令ps,可以看到有标记为的进程就是僵尸进程。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main(){pid_t fpid = fork();if(fpid < 0){printf("创建子进程失败\n");return fpid;}else if(fpid == 0){exit(-1);}else if(fpid > 0){while(1);}return 0;
}

这里可以用 wait 和 waitpid 函数回收子进程

2.怎样来清除僵尸进程:

  • 改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用 wait,内核也会向它发送SIGCHLD消息,尽管对默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
  • 把父进程杀掉。父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程。它产生的所有僵尸进程也跟着消失。

linxu学习之进程相关推荐

  1. Linux第六周学习总结——进程额管理和进程的创建

    Linux第六周学习总结--进程额管理和进程的创建 作者:刘浩晨 [原创作品转载请注明出处] <Linux内核分析>MOOC课程http://mooc.study.163.com/cour ...

  2. 超级详细学习了解进程和病毒知识

    超级详细学习了解进程和病毒知识 作者:不详 来源于:黑客在线 发布时间:2007-4-3 10:26:48 超级详细了解进程和病毒知识 第一:进程是什么 进程为应用程序的运行实例,是应用程序的一次动态 ...

  3. Linux内核学习008——进程管理(四)

    Linux内核学习007--进程管理(四) 进程家族树 Unix系统的进程之间存在一个明显的继承关系,所有的进程都是PID为1的init进程的后代.内核在系统启动的最后阶段启动init进程,然后ini ...

  4. UNIX再学习 -- 守护进程(转)

    参看:守护进程 一.什么是守护进程 守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程.它是一个生存期较长的进程,通常独立于控制 ...

  5. Linxu 学习记录

    1.配置Java人环境变量,设置后需要使用命令: source /etc/profile 让配置立即生效. # jdk7 settings JAVA_HOME=/usr/jdk1.7.0_79 JRE ...

  6. Linux系统学习: 进程、重定向和管道指令:xargs 指令的作用是

    进程 为了弄清楚这节课程的内容,也就是管道,我们先来讨论一下进程. 我们知道,应用的可执行文件是放在文件系统里,把可执行文件启动,就会在操作系统里(具体来说是内存中)形成一个应用的副本,这个副本就是进 ...

  7. Python学习_进程multiprocessing 多进程 协程

    进程的简单用法: #!/usr/bin/env python # -*- coding:utf-8 -*- from multiprocessing import Process import tim ...

  8. oracle lms进程 内存,基于oracle 10.2.0.1 rac学习lms进程系列四

    背景 之前,我们了解了lmd进程一些概念,这儿我们学习下另一个重要RAC后台进程,LMS进程. 结论 1,如果lms出现故障,会导致dml事务无法提交,即提交或回退hang住;并且远端节点的DML操作 ...

  9. 当初我要是这么学习「进程和线程」就好了(附带思维导图)

    作者 | cxuan 来源 | Java建设者 本文思维导图 我们平常说的进程和线程更多的是基于编程语言的角度来说的,那么你真的了解什么是线程和进程吗?那么我们就从操作系统的角度来了解一下什么是进程和 ...

最新文章

  1. Java生成XML文件与XML文件的写入
  2. 测试无数据_无数据驱动自动化测试
  3. MySQL性能调优与架构设计——第4章 MySQL安全管理
  4. Hadoop伪分布安装详解(一)
  5. React之回调ref中回调执行次数的问题
  6. 财务一体化项目,进度与计划31
  7. Python办公自动化(六)|自动更新表格,
  8. 正态分布的前世今生:误差分布曲线的确立
  9. PS小技巧 | 不需要抠图的黑白配
  10. 【PHP面向对象(OOP)编程入门教程】20.PHP5接口技术(interface)
  11. 溯光者:超简单,一文读懂显卡型号编码数字、字母怎么看,都是什么意思?
  12. 【IoT】产品经理:人性洞察的底层逻辑
  13. Navicat for mysql 在WIN10下导入SQL不成功解决办法
  14. 手撕BP网络,你值得拥有!
  15. Keil环境添加STC系列单片机
  16. 主流图数据库对比,Neo4j、ArangoDB、OrientDB、JanusGraph、HugeGraph
  17. 基于 flash AS3.0 的BASE64编码与解码类
  18. ETL VS SSIS 开发
  19. 九种方式,教你获取 resources 目录下的文件
  20. VML之带背景的3D图形任意旋转

热门文章

  1. 苹果5s参数_阿昆聊魅族、苹果手机PCB电路板的制造工艺,我们需要精品意识
  2. java swing桌面_Java图形界面swing面板
  3. 五一户外运动装备怎么选,列举出几款不错的户外装备
  4. [PC][SPG][3DM工作室/NBA2K]联合发布《NBA2K9》硬盘破解版
  5. 10个Python简单技巧,让数据分析速度加快不止一倍(附零基础学习资料)
  6. 2400g运行linux,AMD R5 2400G/R3 2200G核显超频测试
  7. 纽约旅游不可错过的帆船体验:带你从不同视角欣赏壮丽城市风光
  8. 初出茅庐的小李第70篇博客之三目运算符求三个数的最大值
  9. 读书笔记之《百年孤独》
  10. 科普名人记(莱昂傅科)