郑州的建设网站有哪些,wordpress如何添加自定义商品链接,建设银行电脑版官方网站,wordpress的网站好用吗1.进程的概念
进程#xff08;Process#xff09;是计算机中的程序关于某数据集合上的一次运行活动#xff0c;
是系统进行资源分配的基本单位#xff0c;是操作系统结构的基础。在早期面向进程设计的计算机结构中#xff0c;进程是程序的基本执行实体#xff1b;在当代…1.进程的概念
进程Process是计算机中的程序关于某数据集合上的一次运行活动
是系统进行资源分配的基本单位是操作系统结构的基础。在早期面向进程设计的计算机结构中进程是程序的基本执行实体在当代面向线程设计的计算机结构中进程是线程的容器。程序是指令、数据及其组织形式的描述进程是程序的实体。
重点
系统进行资源分配的基本单位进程是程序的基本执行实体(包含线程)进程是线程的容器程序是指令、数据及其组织形式的描述进程是程序的实体进程是程序的一次执行--动态的程序包含了所需要实现功能的代码就是一个文件--静态的不同的进程之间是相互独立的指的是存储空间是独立的
进程是60年代初首先由麻省理工学院的MULTICS系统和IBM公司的CTSS/360系统引入的。 [2]
进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源是一个动态的概念是一个活动的实体。它不只是程序的代码还包括当前的活动通过程序计数器的值和处理寄存器的内容来表示。 进程中包含文本区域text region、数据区域data region和堆栈stack region
以上进程中包含的内容通过什么样的形式表现出来的--进程控制块
多道程序了解
多道程序设计技术是在计算机内存中同时存放几道相互独立的程序使它们在管理程序控制下相互穿插运行两个或两个以上程序在计算机系统中同处于开始到结束之间的状态, 这些程序共享计算机系统资源。与之相对应的是单道程序即在计算机内存中只允许一个的程序运行。
对于一个单CPU系统来说程序同时处于运行状态只是一种宏观上的概念他们虽然都已经开始运行但就微观而言任意时刻CPU上运行的程序只有一个。
操作系统引入进程的概念的原因:
从理论角度看是对正在运行的程序过程的抽象
从实现角度看是一种数据结构目的在于清晰地刻画动态系统的内在规律有效管理和调度进入计算机系统主存储器运行的程序。 进程组成程序 数据 进程控制块
进程的创建数量
cat /proc/sys/kernel/pid_max 进程的状态
就绪态进程已经具备执行的一切条件正在等待分配 CPU 的处理时间。
执行态该进程正在占用 CPU 运行。
等待态进程因不具备某些执行条件而暂时无法继续执行的状态。 进程控制块
位置
/usr/src/linux-headers-5.4.0-84-generic/include/linux/sched.h 进程控制块中包含的内容
调度数据:
进程的状态、标志、优先级、调度策略等。
时间数据:
创建该进程的时间、在用户态的运行时间、在内核态的运行时间等。
文件系统数据:
umask 掩码、文件描述符表等。内存数据、进程上下文、进程标识进程号
struct task_struct {/** offsets of these are hardcoded elsewhere - touch with care*/volatile long state; /* -1 unrunnable, 0 runnable, 0 stopped */ //进程当前的状态unsigned long flags; /* per process flags, defined below */ //反应进程状态的信息但不是运行状态定义见下int sigpending; //进程收到了信号但尚未处理mm_segment_t addr_limit; /* thread address space: //虚存地址上限0-0xBFFFFFFF for user-thead0-0xFFFFFFFF for kernel-thread*/struct exec_domain *exec_domain;volatile long need_resched; //与进程调度有关表示用户从系统空间按返回用户空间要执行的一次调度unsigned long ptrace;int lock_depth; /* Lock depth *//** offset 32 begins here on 32-bit platforms. We keep* all fields in a single cacheline that are needed for* the goodness() loop in schedule().*/long counter; //与进程调度相关long nice;unsigned long policy; //实用于本进程的调度政策struct mm_struct *mm;int processor;/** cpus_runnable is ~0 if the process is not running on any* CPU. Its (1 cpu) if its running on a CPU. This mask* is updated under the runqueue lock.** To determine whether a process might run on a CPU, this* mask is AND-ed with cpus_allowed.*/unsigned long cpus_runnable, cpus_allowed;/** (only the next pointer fits into the cacheline, but* thats just fine.)*/struct list_head run_list;unsigned long sleep_time;struct task_struct *next_task, *prev_task; //内核会对每一个进程做点什么事情的时候常常需要将其连成一个队列这2个指针用于这个目的struct mm_struct *active_mm;struct list_head local_pages;unsigned int allocation_order, nr_local_pages;/* task state */struct linux_binfmt *binfmt;//应用文件格式int exit_code, exit_signal;int pdeath_signal; /* The signal sent when the parent dies *//* ??? */unsigned long personality; //进程的个性化信息详细见下int did_exec:1;unsigned task_dumpable:1;pid_t pid; //进程号pid_t pgrp;pid_t tty_old_pgrp;pid_t session;pid_t tgid;/* boolean value for session group leader */int leader;/* * pointers to (original) parent process, youngest child, younger sibling,* older sibling, respectively. (p-father can be replaced with * p-p_pptr-pid)*/struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; //用于族谱信息的例如p_opptr指向父进程struct list_head thread_group;/* PID hash table linkage. */struct task_struct *pidhash_next;struct task_struct **pidhash_pprev; //pid是随机分配的我们常常使用kill pid想进程发送信号大部分人认为是杀死进程其实这是个发送信号的指令默认的参数为杀死。如果想暂停某进程只需kill STOP 进程的PID这里可以看到根据pid寻找进程的操作是经常被使用的而pid又是随机分配于是这里边用这2个指针指向一个杂凑数组数组是按照杂凑的算法以pid为关键字建立方便根据pid来寻找task_structwait_queue_head_t wait_chldexit; /* for wait4() */struct completion *vfork_done; /* for vfork() */unsigned long rt_priority; //优先级unsigned long it_real_value, it_prof_value, it_virt_value;unsigned long it_real_incr, it_prof_incr, it_virt_incr;struct timer_list real_timer;struct tms times; //运行时间的总汇unsigned long start_time;long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; //在多个处理器上运行于系统空间和用户空间的时间
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;//发生页面异常的次数和换入换出的次数int swappable:1;
/* process credentials */uid_t uid,euid,suid,fsuid;gid_t gid,egid,sgid,fsgid; //与文件权限有关的int ngroups;gid_t groups[NGROUPS];kernel_cap_t cap_effective, cap_inheritable, cap_permitted; //权限比如该进程是否有权限从新引导系统这里是大概介绍int keep_capabilities:1;struct user_struct *user; //指向该进程拥有的用户
/* limits */struct rlimit rlim[RLIM_NLIMITS]; //进程对各种资源使用数量的限制详细见下unsigned short used_math;char comm[16];
/* file system info */int link_count, total_link_count;struct tty_struct *tty; /* NULL if no tty */unsigned int locks; /* How many file locks are being held */
/* ipc stuff */struct sem_undo *semundo;struct sem_queue *semsleeping;
/* CPU-specific state of this task */struct thread_struct thread;
/* filesystem information */struct fs_struct *fs;
/* open file information */struct files_struct *files;
/* namespace */struct namespace *namespace;
/* signal handlers */spinlock_t sigmask_lock; /* Protects signal and blocked */struct signal_struct *sig;sigset_t blocked;struct sigpending pending;unsigned long sas_ss_sp;size_t sas_ss_size;int (*notifier)(void *priv);void *notifier_data;sigset_t *notifier_mask;/* Thread group tracking */u32 parent_exec_id;u32 self_exec_id;
/* Protection of (de-)allocation: mm, files, fs, tty */spinlock_t alloc_lock;/* journalling filesystem info */void *journal_info;
};#define TASK_RUNNING 0 //不是表示正在运行而是表示可以被调用
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_ZOMBIE 4
#define TASK_STOPPED 8 //对应于task_struct中的state进程运行状态//对应task_struct的flag
#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs *//* Not implemented yet, only for 486*/
#define PF_STARTING 0x00000002 /* being created */
#define PF_EXITING 0x00000004 /* getting shut down */
#define PF_FORKNOEXEC 0x00000040 /* forked but didnt exec */
#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */
#define PF_DUMPCORE 0x00000200 /* dumped core */
#define PF_SIGNALED 0x00000400 /* killed by a signal */
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
#define PF_MEMDIE 0x00001000 /* Killed for out-of-memory */
#define PF_FREE_PAGES 0x00002000 /* per process page freeing */
#define PF_NOIO 0x00004000 /* avoid generating further I/O */
#define PF_FSTRANS 0x00008000 /* inside a filesystem transaction */#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) *///进程的个性化信息
enum {MMAP_PAGE_ZERO 0x0100000,ADDR_LIMIT_32BIT 0x0800000,SHORT_INODE 0x1000000,WHOLE_SECONDS 0x2000000,STICKY_TIMEOUTS 0x4000000,ADDR_LIMIT_3GB 0x8000000,
};/** Personality types.** These go in the low byte. Avoid using the top bit, it will* conflict with error returns.*/
enum {PER_LINUX 0x0000,PER_LINUX_32BIT 0x0000 | ADDR_LIMIT_32BIT,PER_SVR4 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,PER_SVR3 0x0002 | STICKY_TIMEOUTS | SHORT_INODE,PER_SCOSVR3 0x0003 | STICKY_TIMEOUTS |WHOLE_SECONDS | SHORT_INODE,PER_OSR5 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS,PER_WYSEV386 0x0004 | STICKY_TIMEOUTS | SHORT_INODE,PER_ISCR4 0x0005 | STICKY_TIMEOUTS,PER_BSD 0x0006,PER_SUNOS 0x0006 | STICKY_TIMEOUTS,PER_XENIX 0x0007 | STICKY_TIMEOUTS | SHORT_INODE,PER_LINUX32 0x0008,PER_LINUX32_3GB 0x0008 | ADDR_LIMIT_3GB,PER_IRIX32 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */PER_IRIXN32 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */PER_IRIX64 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */PER_RISCOS 0x000c,PER_SOLARIS 0x000d | STICKY_TIMEOUTS,PER_UW7 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO,PER_HPUX 0x000f,PER_OSF4 0x0010, /* OSF/1 v4 */PER_MASK 0x00ff,
};//进程资源的限制对应task_struct中的struct rlimit rlim[RLIM_NLIMITS],RLIM_NLIMITS的值是11代表11项资源分别是
#define RLIMIT_CPU 0 /* CPU time in ms */
#define RLIMIT_FSIZE 1 /* Maximum filesize */
#define RLIMIT_DATA 2 /* max data size */
#define RLIMIT_STACK 3 /* max stack size */
#define RLIMIT_CORE 4 /* max core file size */
#define RLIMIT_RSS 5 /* max resident set size */
#define RLIMIT_NPROC 6 /* max number of processes */
#define RLIMIT_NOFILE 7 /* max number of open files */
#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */
#define RLIMIT_AS 9 /* address space limit */
#define RLIMIT_LOCKS 10 /* maximum file locks held */
进程相关的几个概念
进程号用于区分不同的进程类似于ID号
每个进程都由一个进程号来标识其类型为 pid_t进程号的范围 0 32767。
进程号总是唯一的但进程号可以重用。当一个进程终止后其进程号就可以再次使
用了。
在 linux 系统中进程号由 0 开始。
进程号为 0 及 1 的进程由内核创建。
进程号为 0 的进程通常是调度进程常被称为交换进程(swapper)。进程号为 1
的进程通常是 init 进程。
除调度进程外在 linux 下面所有的进程都由进程 init 进程直接或者间接创建。
进程号(PID)
标识进程的一个非负整型数。
父进程号(PPID)
任何进程(除 init 进程)都是由另一个进程创建该进程称为被创建进程
的父进程对应的进程号称为父进程号(PPID)。
进程组号(PGID)
进程组是一个或多个进程的集合。他们之间相互关联进程组可以接收同一终端的各种信号关联的进程有一个进程组号(PGID)。
进程号相关的几个函数
Linux 操作系统提供了三个获得进程号的函数 getpid()、 getppid()、 getpgid()
#include sys/types.h
#include unistd.h
pid_t getpid(void)
功能获取本进程号(PID)
pid_t getppid(void)
功能获取调用此函数的进程的父进程号(PPID)
pid_t getpgid(pid_t pid)
功能获取进程组号(PGID)参数为 0 时返回当前 PGID否则返回参数指定的进程的
PGID#include stdio.h
#include sys/types.h //open
#include sys/stat.h //open
#include fcntl.h //open
#include unistd.h //read write close
#include errno.h //perrorint main(void)
{//getpid()、 getppid()、 getpgid()pid_t pid_n0;pid_t pid_c0;pid_cgetpid();printf(当前进程的ID号%d\n,pid_c);pid_ngetppid();printf(当前进程的父进程的ID号%d\n,pid_n);pid_ngetpgid(pid_c);printf(当前进程的组ID号%d\n,pid_n);return 0;
} fork函数
#include sys/types.h
#include unistd.h
pid_t fork(void);
pid_t vfork(void);//我们不是用
创建一个新进程
pid_t fork(void)
功能:
fork()函数用于从一个已存在的进程中创建一个新进程新进程称为子进程原进
程称为父进程。
返回值:
成功子进程中返回 0父进程中返回子进程 ID。
失败返回-1。
使用 fork 函数得到的子进程是父进程的一个复制品它从父进程处继承了整个进程的地址空间。
地址空间:
包括进程上下文、进程堆栈、打开的文件描述符、信号控制设定、进程优先级、进程组号等--PCB进程控制块中。
子进程所独有的只有它的进程号计时器等。因此使用 fork 函数的代价是很大的。 #include stdio.h
#include sys/types.h //open
#include sys/stat.h //open
#include fcntl.h //open
#include unistd.h //read write close
#include errno.h //perrorint main(void)
{pid_t pid;pidfork();//调用一次执行两次返回三个结果if(pid0)//子进程{while(1){printf(当前进入子进程\n);sleep(1);} }else if(pid0){while(1){printf(当前进入父进程\n);sleep(1);}}return 0;
} 通过结果可得父进程和子进程的执行是没有先后顺序的随机的无法判断的
具体的话需要去看内核中的调度算法
子进程和父进程是相互独立的
#include stdio.h
#include sys/types.h //open
#include sys/stat.h //open
#include fcntl.h //open
#include unistd.h //read write close
#include errno.h //perrorint val10;
int main(void)
{int data20;pid_t pid;pidfork();if(pid0)//子进程{while(1){printf(当前进入子进程\n);sleep(1);printf(val%d\n data%d\n,val,data);}}else if(pid0)//父进程{while(1){val;data;printf(当前进入父进程\n);sleep(1);printf(father_val%d\n father_data%d\n,val,data);}}return 0;
} fork函数的作用 vfork函数
pid_t vfork(void)
功能
vfork 函数和 fork 函数一样都是在已有的进程中创建一个新的进程但它们创
建的子进程是有区别的。
返回值:
创建子进程成功则在子进程中返回 0,父进程中返回子进程 ID。出错则返回-1。
vfork函数和fork函数的区别
fork()函数和vfork()函数都是用于创建新进程的系统调用函数它们之间有以下区别
内存管理
fork()函数会创建一个子进程子进程将复制父进程的完整内存空间包括代码段、数据段和堆栈等。子进程和父进程将拥有相同的内存副本但是各自的内存是独立的不会相互影响。vfork()函数创建的子进程与父进程共享内存空间。子进程会暂时使用父进程的地址空间直到调用exec()或者exit()函数。在这之前子进程对内存的修改会直接影响到父进程。
执行顺序
fork()函数调用后父进程和子进程都会继续执行但是执行顺序是不确定的由操作系统的调度决定。vfork()函数调用后子进程会先执行而父进程会被阻塞直到子进程调用exec()或者exit()函数。
效率
fork()函数复制整个父进程的内存空间涉及到页表的复制和写时复制Copy-on-Write因此相对较慢。vfork()函数仅仅是共享父进程的内存空间因此效率更高。
用途
fork()函数通常用于创建一个完全独立的子进程使父进程和子进程可以并行执行不同的任务。vfork()函数一般用于创建一个临时的“子进程”在该子进程调用exec()或者exit()之前可以利用共享的地址空间来执行一些特定任务比如调用一个新程序。
#include stdio.h
#include stdlib.h#include sys/types.h#include dirent.h#include string.h#include unistd.hint main(int argv,char *argc[])
{int data20;int i0;pid_t pid;pidvfork();if(pid0)//子进程{for(i0;i3;i){printf(当前进入子进程\n);sleep(1);// printf(val%d\n data%d\n,val,data);}exit(1);}else if(pid0)//父进程{while(1){printf(当前进入父进程\n);sleep(1);}}return 0;
} 查看进程-PS
Linux ps 英文全拼process status命令用于显示当前进程的状态类似于windows 的任务管理器。ps [options] [--help]
参数内容
-A 列出所有的进程
-w 显示加宽可以显示较多的资讯
-au 显示较详细的资讯
-aux 显示所有包含其他使用者的进程ps -aux|grep a.out //查找a.out进程 使用ps指令进行全局搜索通过管道输出我们想要的a.out
|--管道
ps -aux
au(x) 输出格式 :
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
USER: 行程拥有者
PID: pid
%CPU: 占用的 CPU 使用率
%MEM: 占用的记忆体使用率
VSZ: 占用的虚拟记忆体大小
RSS: 占用的记忆体大小
TTY: 终端的次要装置号码 (minor device number of tty)
STAT: 该行程的状态:D: 无法中断的休眠状态 (通常 IO 的进程)R: 正在执行中S: 静止状态T: 暂停执行Z: 不存在但暂时无法消除W: 没有足够的记忆体分页可分配: 高优先序的行程N: 低优先序的行程L: 有记忆体分页分配并锁在记忆体内 (实时系统或捱A I/O)
START: 行程开始时间
TIME: 执行的时间
COMMAND:所执行的指令 进程的挂起和等待
父子进程有时需要简单的进程间同步如父进程等待子进程的结束。
linux 下提供了以下两个等待函数 wait()、 waitpid()。 #include sys/types.h#include sys/wait.hpid_t wait(int *wstatus); //阻塞性
等待子进程终止如果子进程终止了此函数会回收子进程的资源。
调用 wait 函数的进程会挂起直到它的一个子进程退出或收到一个不能被忽
视的信号时才被唤醒。
若调用进程没有子进程或它的子进程已经结束该函数立即返回。
参数
函数返回时参数 status 中包含子进程退出时的状态信息。子进程的退出信息在
一个 int 中包含了多个字段用宏定义可以取出其中的每个字段。
取出子进程的退出信息WIFEXITED(status)
如果子进程是正常终止的取出的字段值非零。WEXITSTATUS(status)
返回子进程的退出状态退出状态保存在 status 变量的 8~16 位。在用此宏前
应先用宏 WIFEXITED 判断子进程是否正常退出正常退出才可以使用此宏。返回值
如果执行成功则返回子进程的进程号。
出错返回-1失败原因存于 errno 中。 pid_t waitpid(pid_t pid, int *wstatus, int options);功能
等待子进程终止如果子进程终止了此函数会回收子进程的资源。
返回值:
如果执行成功则返回子进程 ID。
出错返回-1失败原因存于 errno 中。 参数 pid 的值有以下几种类型
pid0
等待进程 ID 等于 pid 的子进程。
pid0
等待同一个进程组中的任何子进程如果子进程已经加入了别的进程组
waitpid 不会等待它。
pid-1
等待任一子进程此时 waitpid 和 wait 作用一样。
pid-1
等待指定进程组中的任何子进程这个进程组的 ID 等于 pid 的绝对值。
status 参数中包含子进程退出时的状态信息。
options 参数能进一步控制 waitpid 的操作
0
同 wait阻塞父进程等待子进程退出。
WNOHANG
没有任何已经结束的子进程则立即返回。
WUNTRACED
如果子进程暂停了则此函数马上返回并且不予以理会子进程的结束状态。
跟踪调试很少用到
#include stdio.h
#include stdlib.h
#include sys/types.h //open
#include sys/stat.h //open
#include fcntl.h //open
#include unistd.h //read write close
#include errno.h //perror
#include sys/wait.hint val10;
int main(void)
{int data20;int count0;pid_t pid;int sta0;pidfork();if(pid0)//子进程{for(int i0;i3;i){count;printf(当前进入子进程--%d\n,count);sleep(1);} exit(1);}else if(pid0)//父进程{wait(sta);if(WIFEXITED(sta)!0) {printf(当前执行的子进程已经退出%d\n,WEXITSTATUS(sta));}printf(父进程即将在三秒后退出......\n);sleep(3);}return 0;
} waitpid--非阻塞
#include stdio.h
#include stdlib.h
#include sys/types.h //open
#include sys/stat.h //open
#include fcntl.h //open
#include unistd.h //read write close
#include errno.h //perror
#include sys/wait.hint val10;
int main(void)
{int data20;int count0;pid_t pid;int sta0;pidfork();if(pid0)//子进程{for(int i0;i3;i){count;printf(当前进入子进程--%d\n,count);sleep(1);} exit(1);}else if(pid0)//父进程{// waitpid(pid,sta,0);//阻塞性waitpid(0,sta,WNOHANG);//非阻塞性printf(父进程即将在三秒后退出......\n);sleep(3); }return 0;
}
waitpid(0,sta,WNOHANG); waitpid(pid,sta,0); 僵尸进程和孤儿进程
僵尸进程危害较大
僵尸进程是指子进程已经终止但是父进程尚未处理其终止状态的进程。僵尸进程在操作系统中存在一段时间直到父进程通过调用适当的函数来获取子进程的终止状态。
僵尸进程的危害
僵尸进程虽然不会直接导致系统崩溃但它们可能会产生以下危害
系统资源浪费: 僵尸进程在操作系统中占用资源包括进程表项、内存、文件描述符等。如果产生大量的僵尸进程将占用宝贵的系统资源导致系统性能下降。进程表溢出: 系统同时能够存在的进程数量是有限的。当产生过多的僵尸进程并且父进程没有处理它们时进程表可能会耗尽导致无法创建新的进程。子进程信息丢失: 僵尸进程的存在意味着父进程无法获取子进程的终止状态。父进程可能无法获知子进程是如何终止的无法判断其是否以预期的方式退出导致无法正确处理异常情况。安全问题: 如果僵尸进程的父进程异常终止或者其他原因导致父进程无法再处理僵尸进程那么这些僵尸进程可能会被系统进程如 init 进程接管。这可能导致进程资源泄漏和系统安全问题。init进程是我们的Ubuntu启动后运行的第一个进程--祖先进程 综上所述虽然僵尸进程本身并不直接威胁系统稳定性但它们会占用系统资源、导致进程表溢出并可能导致子进程信息丢失和安全问题。因此及时处理僵尸进程是保持系统健康运行的重要任务。
孤儿进程危害相对较小
孤儿进程是指其父进程已经终止或被其他进程接管而无法接收其终止状态的进程。在Unix-like操作系统中孤儿进程会被特殊的init进程进程ID为1接管init进程会定期检查并回收这些孤儿进程。
孤儿进程可能产生的主要原因有两种情况
当父进程比子进程更早地终止时子进程可能会变成孤儿进程。父进程在子进程终止前未能调用wait() waitpid()
孤儿进程可能会导致以下问题
资源泄漏孤儿进程占用系统资源如进程表项、内存、打开的文件等可能会导致资源浪费特别是当大量孤儿进程存在时。进程状态无法正确追踪由于其父进程无法获取孤儿进程的终止状态可能会导致无法及时知道进程是如何终止的无法正确处理异常情况。
为了避免孤儿进程的产生父进程通常可以采取以下几种方式之一
正确地等待子进程终止父进程可以使用wait()或waitpid()等类似函数主动等待子进程终止并获取其终止状态在子进程终止后及时处理。忽略SIGCHLD信号通过忽略SIGCHLD信号使父进程不接收到子进程终止的信号这样子进程就成为孤儿进程并由init进程接管和回收。
总之孤儿进程可能导致资源浪费和进程状态追踪问题但由于系统的处理机制孤儿进程通常不会引发严重的问题。父进程可以通过适当的方式来避免或处理孤儿进程。
#include stdio.h
#include stdlib.h
#include sys/types.h //open
#include sys/stat.h //open
#include fcntl.h //open
#include unistd.h //read write close
#include errno.h //perror
#include sys/wait.hint val10;
int sta0;
int main(void)
{int data20;pid_t pid;pidfork();if(pid0)//子进程{int count0;while(1){count;printf(当前进入子进程\n);sleep(1);printf(val%d\n data%d\n,val,data);if(count5){exit(1);}}}else if(pid0)//父进程{while(1){waitpid(0,sta,WNOHANG);//非阻塞性val;data;printf(当前进入父进程\n);sleep(1);printf(father_val%d\n father_data%d\n,val,data);}}return 0;
} 守护进程
守护进程--后台进程
守护进程daemon是在后台运行的一种特殊类型的进程它通常在系统启动时启动并一直运行不受用户登录和注销的影响。守护进程通常在操作系统中执行一些特定的任务或提供一些系统服务。
以下是一些守护进程的特点
在后台运行守护进程在后台默默地运行不与用户交互并且通常没有控制终端。独立于登录会话守护进程与用户登录和注销无关它们独立于用户的操作而运行。
守护进程有父进程吗守护进程是没有父进程
没有标准输入输出守护进程通常没有标准输入和输出因为它们不与控制终端进行交互。长期运行守护进程通常在系统启动时启动并一直运行直到系统关闭或主动停止。提供系统服务守护进程通常提供一些系统服务如网络服务如HTTP服务器、FTP服务器、日志服务、任务调度服务等。
创建守护进程的过程通常涉及以下步骤
分离控制终端通过调用fork()创建子进程然后在子进程中调用setsid()将子进程从终端会话中分离出来。更改工作目录通常会将守护进程的工作目录切换到根目录或其他适当的目录。重定向标准文件描述符关闭或重定向标准输入、标准输出和标准错误文件描述符到/dev/null或其他适当的日志文件。执行守护进程任务在守护进程中执行相应的任务并保持长期运行。
守护进程的创建可以使用不同编程语言和操作系统接口来实现具体的实现方式可能会有一些差异。一些常见的守护进程有sshdSSH服务器守护进程、httpdHTTP服务器守护进程等。
setsid
NAMEsetsid - creates a session and sets the process group ID创建会话并设置进程组IDSYNOPSIS#include sys/types.h#include unistd.hpid_t setsid(void);
如果调用进程不是进程组的领导者setsid将创建一个新会话。呼叫过程是领导者使其会话ID与其
进程ID相同。调用过程也成为会话中新流程组的流程组长即使其流程组ID与其流程相同ID。调用进程将是新进程组和新会话中的唯一进程。最初新会话没有控制终端。关于会话如何获取控制终端的细节
请参阅凭据7。返回值
成功后将返回调用进程的新会话ID。出现错误时返回pid_t-1并设置errno以指示错误。
错误
EPERM任何进程的进程组ID等于调用进程的PID。
进程的终止
atexit()函数和exit()函数都是用于在程序退出时执行特定任务的函数但它们之间有一些区别。
调用顺序atexit()函数允许注册多个退出处理函数它们将按照注册的顺序逆向执行。而exit()函数只能执行一个退出处理函数即使注册了多个。灵活性atexit()函数比exit()函数更灵活可以在程序的多个地方调用atexit()注册不同的退出处理函数而exit()函数只能在程序的一个地方调用。返回值及退出码atexit()函数没有返回值而exit()函数会终止程序的执行并将退出码通过参数传递给exit()函数返回给操作系统退出码可用于表示程序退出状态的信息。调用时机atexit()函数注册的退出处理函数在exit()函数被调用时才会执行而exit()函数本身是立即被调用的它会终止程序的执行并立即执行退出处理函数。是否终止进程atexit()函数不能直接终止进程的执行而exit()函数会终止进程的执行并立即返回到操作系统。
进程的终止函数
void exit(int value);//属于库函数进行了封装
void _exit(int value);//初拥系统调度中去使用的 补充部分
终端部分
#include unistd.h
char *ttyname(int fd);
参数:
fd是文件描述符它表示一个打开的文件或者是标准输入、标准输出或标准错误的文件描述符。如果
fd是有效的且与终端设备相关联ttyname()函数会返回一个指向终端设备文件名的指针。如果
fd不是终端设备或者无效的ttyname()函数返回NULL。
作用
用于获取指定文件描述符所关联的终端设备文件的路径名。
#include stdio.h
#include stdlib.h
#include sys/types.h //open
#include sys/stat.h //open
#include fcntl.h //open
#include unistd.h //read write close
#include errno.h //perror
#include sys/wait.h
int sta0;
int val;
int main(void)
{pid_t pid;pidfork();if(pid0)//子进程{printf(子进程执行成功\n);scanf(%d,val);printf(子进程--当前终端为%s--data%d--pid%d\n,ttyname(0),val,getpid());// printf(父进程pid%d\n,ttyname(0),val,getpppid());exit(1);}else if(pid0)//父进程{// waitpid(pid,sta,0);//阻塞性printf(父进程正在运行\n);scanf(%d,val);printf(父进程--当前终端为%s--data%d--pid%d\n,ttyname(0),val,getpid());}return 0;
} 进程组和会话
进程组和会话都是用于管理和组织进程的概念但它们在层级和作用上有所区别。下面列出了它们的主要区别
层级关系:
进程组是操作系统中一组相关进程的集合这些进程拥有相同的进程组ID。进程组使得可以同时向组内的所有进程发送信号例如中断或终止信号。这对于控制终端中运行的命令和它们衍生的子进程特别有用。会话是一个或多个进程组的集合这些进程共享相同的会话ID会话本质上代表一个用户的登录实例。会话控制了终端和进程之间的交互并且通常在用户登陆时开始在用户注销时结束。
会话当前某一个用户登录所能控制的所有资源集合
进程的关联性:
进程在创建时会加入创建它的进程的组除非特别指定加入另一个组同一个进程组内的进程通常是协同工作或是具有相同行为特征的一组进程。会话可以包含多个进程组。一个会话开始于一个登录shell或用户启动的会话领导者进程并且可能包含多个协作的进程组这些进程组可以独立进行任务。
前台和后台控制:
进程组一个会话中可以有多个进程组但在任何时刻只有一个进程组可以是前台进程组可接收来自终端的输入其他的都是后台进程组。会话管理前台和后台进程组可以控制终端访问例如只有前台进程组可以从终端读取输入。
生命周期:
进程组的生命周期通常与组内进程的创建和结束相关特定任务完成或用户中断可能导致进程组的解散。会话的生命周期通常与用户会话相关。当用户登录时会话开始当用户注销或会话领导者进程结束时会话结束。
终端控制权:
会话与控制终端controlling terminal相关联。会话中的前台进程组可以接收终端的输入并处理终端的输出。进程组并不直接与控制终端相关联控制终端的概念在会话层级中被管理。
简而言之进程组是组织相关进程的一种方式而会话是管理用户登录及其所启动进程组的更高级抽象。会话可以控制前台和后台进程组管理与控制终端的交互并在用户登陆和注销时开始和结束。
进程组和会话的概念在多进程编程和作业控制等领域有着广泛的应用可以通过管理进程组和会话来实现对进程的控制和协调。
进程组本质就是多个进程的集合
会话指的就是多个进程组的集合 PS ajx---查看进程组和会话
PPID--父进程ID
PID--当前进程
PGID--组ID
SID--会话
进程组框架 会话的创建步骤
1) 调用进程不能是进程组组长该进程变成新会话首进程(session header)
2) 该调用进程是组长进程则出错返回
3) 该进程成为一个新进程组的组长进程
4) 需有 root 权限(ubuntu 不需要)
5) 新会话丢弃原有的控制终端该会话没有控制终端
6) 建立新会话时先调用 fork, 父进程终止子进程调用 setsid设置会话的函数就是setsid函数。
获取会话pid_t getsid(pid_t pid);