Linux系统开发7 进程关系,守护进程

本文谢绝转载原文来自http://990487026.blog.51cto.com


<大纲>

Linux系统开发7  进程关系守护进程
	终端
	网络终端
	Linux PCB结构体信息
	进程组
	修改子进程、父进程的组ID
	会话组
	设置一个会话脱离控制终端
	生成一个新的会话
	守护进程
	守护进程模板
	获取当前系统时间	

 终端

在UNIX系统中用户通过终端登录系统后得到一个Shell进程这个终端成为Shell进

程的控制终端Controlling Terminal在讲进程时讲过控制终端是保存在PCB中的信

息而我们知道fork会复制PCB中的信息因此由Shell进程启动的其它进程的控制终端也是

这个终端。默认情况下没有重定向每个进程的标准输入、标准输出和标准错误输出都

指向控制终端进程从标准输入读也就是读用户的键盘输入进程往标准输出或标准错误输

出写也就是输出到显示器上。信号中还讲过在控制终端输入一些特殊的控制键可以给前台

进程发信号例如Ctrl-C表示SIGINTCtrl-\表示SIGQUIT。

init-->fork-->exec-->getty-->用户输入帐号-->login-->输入密码-->exec-->shell

文件与I/O中讲过每个进程都可以通过一个特殊的设备文件/dev/tty访问它的控制终

端。事实上每个终端设备都对应一个不同的设备文件/dev/tty提供了一个通用的接口一

个进程要访问它的控制终端既可以通过/dev/tty也可以通过该终端设备所对应的设备文件来

访问。ttyname函数可以由文件描述符查出对应的文件名该文件描述符必须指向一个终端

设备而不能是任意文件。下面我们通过实验看一下各种不同的终端所对应的设备文件名。

硬件驱动程序负责读写实际的硬件设备比如从键盘读入字符和把字符输出到显示器

线路规程像一个过滤器对于某些特殊字符并不是让它直接通过而是做特殊处理比如在

键盘上按下Ctrl-Z对应的字符并不会被用户程序的read读到而是被线路规程截获解释

成SIGTSTP信号发给前台进程通常会使该进程停止。线路规程应该过滤哪些字符和做哪些

特殊处理是可以配置的。

【看图】

ttyname 参数所代表的文件描述词为一终端机。

不同终端显示不同终端的名字
[email protected]:~/linux_c/进程间关系$ cat ttyname.c 
#include <unistd.h>
#include <stdio.h>
int main(void)
{
	printf("fd 0:%s\n",ttyname(0));
	printf("fd 1:%s\n",ttyname(1));
	printf("fd 2:%s\n",ttyname(2));
	printf("fd 3:%s\n",ttyname(3));
	return 0;
}

远程SSH连接编译运行
[email protected]:~/linux_c/进程间关系$ gcc ttyname.c && ./a.out  
fd 0:/dev/pts/9
fd 1:/dev/pts/9
fd 2:/dev/pts/9
fd 3:(null)
[email protected]:~/linux_c/进程间关系$ 

在标准终端运行 ,切换终端:ctrl+alt+F2
gcc ttyname.c && ./a.out 
fd 0:/dev/tty2
fd 1:/dev/tty2
fd 2:/dev/tty2
fd 3:(null)

网络终端

虚拟终端或串口终端的数目是有限的虚拟终端(字符控制终端)一般就是/dev/tty1/

dev/tty6六个串口终端的数目也不超过串口的数目。然而网络终端或图形终端窗口的数目

却是不受限制的这是通过伪终端Pseudo TTY实现的。一套伪终端由一个主设备PTY

Master和一个从设备PTY Slave组成。主设备在概念上相当于键盘和显示器只不过

它不是真正的硬件而是一个内核模块操作它的也不是用户而是另外一个进程。从设备和上

面介绍的/dev/tty1这样的终端设备模块类似只不过它的底层驱动程序不是访问硬件而是

访问主设备。网络终端或图形终端窗口的Shell进程以及它启动的其它进程都会认为自己的

控制终端是伪终端从设备例如/dev/pts/0、/dev/pts/1等。下面以telnet为例说明网络登

录和使用伪终端的过程。

如果telnet客户端和服务器之间的网络延迟较大我们会观察到按下一个键之后要过几

秒钟才能回显到屏幕上。这说明我们每按一个键telnet客户端都会立刻把该字符发送给服务

器然后这个字符经过伪终端主设备和从设备之后被Shell进程读取同时回显到伪终端从

设备回显的字符再经过伪终端主设备、telnetd服务器和网络发回给telnet客户端显示

给用户看。也许你会觉得吃惊但真的是这样每按一个键都要在网络上走个来回

【看图】

Linux PCB结构体信息

# uname -rm
4.4.0-34-generic x86_64

# cp  /usr/src/linux-headers-4.4.0-34/include/linux/sched.h ./
# vim ./sched.h  +1380

struct task_struct {
	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
	void *stack;
	atomic_t usage;
	unsigned int flags;	/* per process flags, defined below */
	unsigned int ptrace;

#ifdef CONFIG_SMP
	struct llist_node wake_entry;
	int on_cpu;
	unsigned int wakee_flips;
	unsigned long wakee_flip_decay_ts;
	struct task_struct *last_wakee;

	int wake_cpu;
#endif
	int on_rq;

	int prio, static_prio, normal_prio;
	unsigned int rt_priority;
	const struct sched_class *sched_class;
	struct sched_entity se;
	struct sched_rt_entity rt;
#ifdef CONFIG_CGROUP_SCHED
	struct task_group *sched_task_group;
#endif
	struct sched_dl_entity dl;

#ifdef CONFIG_PREEMPT_NOTIFIERS
	/* list of struct preempt_notifier: */
	struct hlist_head preempt_notifiers;
#endif

#ifdef CONFIG_BLK_DEV_IO_TRACE
	unsigned int btrace_seq;
#endif

	unsigned int policy;
	int nr_cpus_allowed;
	cpumask_t cpus_allowed;

#ifdef CONFIG_PREEMPT_RCU
	int rcu_read_lock_nesting;
	union rcu_special rcu_read_unlock_special;
	struct list_head rcu_node_entry;
	struct rcu_node *rcu_blocked_node;
#endif /* #ifdef CONFIG_PREEMPT_RCU */
#ifdef CONFIG_TASKS_RCU
	unsigned long rcu_tasks_nvcsw;
	bool rcu_tasks_holdout;
	struct list_head rcu_tasks_holdout_list;
	int rcu_tasks_idle_cpu;
#endif /* #ifdef CONFIG_TASKS_RCU */

#ifdef CONFIG_SCHED_INFO
	struct sched_info sched_info;
#endif

	struct list_head tasks;
#ifdef CONFIG_SMP
	struct plist_node pushable_tasks;
	struct rb_node pushable_dl_tasks;
#endif

	struct mm_struct *mm, *active_mm;
	/* per-thread vma caching */
	u32 vmacache_seqnum;
	struct vm_area_struct *vmacache[VMACACHE_SIZE];
#if defined(SPLIT_RSS_COUNTING)
	struct task_rss_stat	rss_stat;
#endif
/* task state */
	int exit_state;
	int exit_code, exit_signal;
	int pdeath_signal;  /*  The signal sent when the parent dies  */
	unsigned long jobctl;	/* JOBCTL_*, siglock protected */

	/* Used for emulating ABI behavior of previous Linux versions */
	unsigned int personality;

	/* scheduler bits, serialized by scheduler locks */
	unsigned sched_reset_on_fork:1;
	unsigned sched_contributes_to_load:1;
	unsigned sched_migrated:1;
	unsigned :0; /* force alignment to the next boundary */

	/* unserialized, strictly ‘current‘ */
	unsigned in_execve:1; /* bit to tell LSMs we‘re in execve */
	unsigned in_iowait:1;
#ifdef CONFIG_MEMCG
	unsigned memcg_may_oom:1;
#endif
#ifdef CONFIG_MEMCG_KMEM
	unsigned memcg_kmem_skip_account:1;
#endif
#ifdef CONFIG_COMPAT_BRK
	unsigned brk_randomized:1;
#endif

	unsigned long atomic_flags; /* Flags needing atomic access. */

	struct restart_block restart_block;

	pid_t pid;
	pid_t tgid;

#ifdef CONFIG_CC_STACKPROTECTOR
	/* Canary value for the -fstack-protector gcc feature */
	unsigned long stack_canary;
#endif
	/*
	 * pointers to (original) parent process, youngest child, younger sibling,
	 * older sibling, respectively.  (p->father can be replaced with
	 * p->real_parent->pid)
	 */
	struct task_struct __rcu *real_parent; /* real parent process */
	struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
	/*
	 * children/sibling forms the list of my natural children
	 */
	struct list_head children;	/* list of my children */
	struct list_head sibling;	/* linkage in my parent‘s children list */
	struct task_struct *group_leader;	/* threadgroup leader */

	/*
	 * ptraced is the list of tasks this task is using ptrace on.
	 * This includes both natural children and PTRACE_ATTACH targets.
	 * p->ptrace_entry is p‘s link on the p->parent->ptraced list.
	 */
	struct list_head ptraced;
	struct list_head ptrace_entry;

	/* PID/PID hash table linkage. */
	struct pid_link pids[PIDTYPE_MAX];
	struct list_head thread_group;
	struct list_head thread_node;

	struct completion *vfork_done;		/* for vfork() */
	int __user *set_child_tid;		/* CLONE_CHILD_SETTID */
	int __user *clear_child_tid;		/* CLONE_CHILD_CLEARTID */

	cputime_t utime, stime, utimescaled, stimescaled;
	cputime_t gtime;
	struct prev_cputime prev_cputime;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
	seqlock_t vtime_seqlock;
	unsigned long long vtime_snap;
	enum {
		VTIME_SLEEPING = 0,
		VTIME_USER,
		VTIME_SYS,
	} vtime_snap_whence;
#endif
	unsigned long nvcsw, nivcsw; /* context switch counts */
	u64 start_time;		/* monotonic time in nsec */
	u64 real_start_time;	/* boot based time in nsec */
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
	unsigned long min_flt, maj_flt;

	struct task_cputime cputime_expires;
	struct list_head cpu_timers[3];

/* process credentials */
	const struct cred __rcu *real_cred; /* objective and real subjective task
					 * credentials (COW) */
	const struct cred __rcu *cred;	/* effective (overridable) subjective task
					 * credentials (COW) */
	char comm[TASK_COMM_LEN]; /* executable name excluding path
				     - access with [gs]et_task_comm (which lock
				       it with task_lock())
				     - initialized normally by setup_new_exec */
/* file system info */
	struct nameidata *nameidata;
#ifdef CONFIG_SYSVIPC
/* ipc stuff */
	struct sysv_sem sysvsem;
	struct sysv_shm sysvshm;
#endif
#ifdef CONFIG_DETECT_HUNG_TASK
/* hung task detection */
	unsigned long last_switch_count;
#endif
/* filesystem information */
	struct fs_struct *fs;
/* open file information */
	struct files_struct *files;
/* namespaces */
	struct nsproxy *nsproxy;
/* signal handlers */
	struct signal_struct *signal;
	struct sighand_struct *sighand;

	sigset_t blocked, real_blocked;
	sigset_t saved_sigmask;	/* restored if set_restore_sigmask() was used */
	struct sigpending pending;

	unsigned long sas_ss_sp;
	size_t sas_ss_size;

	struct callback_head *task_works;

	struct audit_context *audit_context;
#ifdef CONFIG_AUDITSYSCALL
	kuid_t loginuid;
	unsigned int sessionid;
#endif
	struct seccomp seccomp;

/* Thread group tracking */
   	u32 parent_exec_id;
   	u32 self_exec_id;
/* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed,
 * mempolicy */
	spinlock_t alloc_lock;

	/* Protection of the PI data structures: */
	raw_spinlock_t pi_lock;

	struct wake_q_node wake_q;

#ifdef CONFIG_RT_MUTEXES
	/* PI waiters blocked on a rt_mutex held by this task */
	struct rb_root pi_waiters;
	struct rb_node *pi_waiters_leftmost;
	/* Deadlock detection and priority inheritance handling */
	struct rt_mutex_waiter *pi_blocked_on;
#endif

#ifdef CONFIG_DEBUG_MUTEXES
	/* mutex deadlock detection */
	struct mutex_waiter *blocked_on;
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
	unsigned int irq_events;
	unsigned long hardirq_enable_ip;
	unsigned long hardirq_disable_ip;
	unsigned int hardirq_enable_event;
	unsigned int hardirq_disable_event;
	int hardirqs_enabled;
	int hardirq_context;
	unsigned long softirq_disable_ip;
	unsigned long softirq_enable_ip;
	unsigned int softirq_disable_event;
	unsigned int softirq_enable_event;
	int softirqs_enabled;
	int softirq_context;
#endif
#ifdef CONFIG_LOCKDEP
# define MAX_LOCK_DEPTH 48UL
	u64 curr_chain_key;
	int lockdep_depth;
	unsigned int lockdep_recursion;
	struct held_lock held_locks[MAX_LOCK_DEPTH];
	gfp_t lockdep_reclaim_gfp;
#endif

/* journalling filesystem info */
	void *journal_info;

/* stacked block device info */
	struct bio_list *bio_list;

#ifdef CONFIG_BLOCK
/* stack plugging */
	struct blk_plug *plug;
#endif

/* VM state */
	struct reclaim_state *reclaim_state;

	struct backing_dev_info *backing_dev_info;

	struct io_context *io_context;

	unsigned long ptrace_message;
	siginfo_t *last_siginfo; /* For ptrace use.  */
	struct task_io_accounting ioac;
#if defined(CONFIG_TASK_XACCT)
	u64 acct_rss_mem1;	/* accumulated rss usage */
	u64 acct_vm_mem1;	/* accumulated virtual memory usage */
	cputime_t acct_timexpd;	/* stime + utime since last update */
#endif
#ifdef CONFIG_CPUSETS
	nodemask_t mems_allowed;	/* Protected by alloc_lock */
	seqcount_t mems_allowed_seq;	/* Seqence no to catch updates */
	int cpuset_mem_spread_rotor;
	int cpuset_slab_spread_rotor;
#endif
#ifdef CONFIG_CGROUPS
	/* Control Group info protected by css_set_lock */
	struct css_set __rcu *cgroups;
	/* cg_list protected by css_set_lock and tsk->alloc_lock */
	struct list_head cg_list;
#endif
#ifdef CONFIG_FUTEX
	struct robust_list_head __user *robust_list;
#ifdef CONFIG_COMPAT
	struct compat_robust_list_head __user *compat_robust_list;
#endif
	struct list_head pi_state_list;
	struct futex_pi_state *pi_state_cache;
#endif
#ifdef CONFIG_PERF_EVENTS
	struct perf_event_context *perf_event_ctxp[perf_nr_task_contexts];
	struct mutex perf_event_mutex;
	struct list_head perf_event_list;
#endif
#ifdef CONFIG_DEBUG_PREEMPT
	unsigned long preempt_disable_ip;
#endif
#ifdef CONFIG_NUMA
	struct mempolicy *mempolicy;	/* Protected by alloc_lock */
	short il_next;
	short pref_node_fork;
#endif
#ifdef CONFIG_NUMA_BALANCING
	int numa_scan_seq;
	unsigned int numa_scan_period;
	unsigned int numa_scan_period_max;
	int numa_preferred_nid;
	unsigned long numa_migrate_retry;
	u64 node_stamp;			/* migration stamp  */
	u64 last_task_numa_placement;
	u64 last_sum_exec_runtime;
	struct callback_head numa_work;

	struct list_head numa_entry;
	struct numa_group *numa_group;

	/*
	 * numa_faults is an array split into four regions:
	 * faults_memory, faults_cpu, faults_memory_buffer, faults_cpu_buffer
	 * in this precise order.
	 *
	 * faults_memory: Exponential decaying average of faults on a per-node
	 * basis. Scheduling placement decisions are made based on these
	 * counts. The values remain static for the duration of a PTE scan.
	 * faults_cpu: Track the nodes the process was running on when a NUMA
	 * hinting fault was incurred.
	 * faults_memory_buffer and faults_cpu_buffer: Record faults per node
	 * during the current scan window. When the scan completes, the counts
	 * in faults_memory and faults_cpu decay and these values are copied.
	 */
	unsigned long *numa_faults;
	unsigned long total_numa_faults;

	/*
	 * numa_faults_locality tracks if faults recorded during the last
	 * scan window were remote/local or failed to migrate. The task scan
	 * period is adapted based on the locality of the faults with different
	 * weights depending on whether they were shared or private faults
	 */
	unsigned long numa_faults_locality[3];

	unsigned long numa_pages_migrated;
#endif /* CONFIG_NUMA_BALANCING */

#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
	struct tlbflush_unmap_batch tlb_ubc;
#endif

	struct rcu_head rcu;

	/*
	 * cache last used pipe for splice
	 */
	struct pipe_inode_info *splice_pipe;

	struct page_frag task_frag;

#ifdef	CONFIG_TASK_DELAY_ACCT
	struct task_delay_info *delays;
#endif
#ifdef CONFIG_FAULT_INJECTION
	int make_it_fail;
#endif
	/*
	 * when (nr_dirtied >= nr_dirtied_pause), it‘s time to call
	 * balance_dirty_pages() for some dirty throttling pause
	 */
	int nr_dirtied;
	int nr_dirtied_pause;
	unsigned long dirty_paused_when; /* start of a write-and-pause period */

#ifdef CONFIG_LATENCYTOP
	int latency_record_count;
	struct latency_record latency_record[LT_SAVECOUNT];
#endif
	/*
	 * time slack values; these are used to round up poll() and
	 * select() etc timeout values. These are in nanoseconds.
	 */
	unsigned long timer_slack_ns;
	unsigned long default_timer_slack_ns;

#ifdef CONFIG_KASAN
	unsigned int kasan_depth;
#endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
	/* Index of current stored address in ret_stack */
	int curr_ret_stack;
	/* Stack of return addresses for return function tracing */
	struct ftrace_ret_stack	*ret_stack;
	/* time stamp for last schedule */
	unsigned long long ftrace_timestamp;
	/*
	 * Number of functions that haven‘t been traced
	 * because of depth overrun.
	 */
	atomic_t trace_overrun;
	/* Pause for the tracing */
	atomic_t tracing_graph_pause;
#endif
#ifdef CONFIG_TRACING
	/* state flags for use by tracers */
	unsigned long trace;
	/* bitmask and counter of trace recursion */
	unsigned long trace_recursion;
#endif /* CONFIG_TRACING */
#ifdef CONFIG_MEMCG
	struct mem_cgroup *memcg_in_oom;
	gfp_t memcg_oom_gfp_mask;
	int memcg_oom_order;

	/* number of pages to reclaim on returning to userland */
	unsigned int memcg_nr_pages_over_high;
#endif
#ifdef CONFIG_UPROBES
	struct uprobe_task *utask;
#endif
#if defined(CONFIG_BCACHE) || defined(CONFIG_BCACHE_MODULE)
	unsigned int	sequential_io;
	unsigned int	sequential_io_avg;
#endif
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
	unsigned long	task_state_change;
#endif
	int pagefault_disabled;
/* CPU-specific state of this task */
	struct thread_struct thread;
/*
 * WARNING: on x86, ‘thread_struct‘ contains a variable-sized
 * structure.  It *MUST* be at the end of ‘task_struct‘.
 *
 * Do not put anything below here!
 */
};

进程组

[email protected]:~/linux_c/进程间关系$ cat process_group.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
	pid_t pid;
	pid = fork();
	if(pid < 0)
	{
		perror("fork");
		exit(1);
	}
	else if(pid == 0)
	{
		printf("child process PID:%d\n",getpid());
		printf("group ID is %d\n",getpgrp());
		printf("group ID is %d\n",getpgid(0));
		printf("group ID is %d\n",getpgid(getpid()));
		exit(1);	//终止子进程运行
	}
	sleep(1);
	printf("\n\n");
	printf("haha  I‘m father!\n");
	printf("parent process ID %d\n",getpid());
	printf("group ID %d\n",getpgrp());

	return 0;
}
[email protected]:~/linux_c/进程间关系$ gcc -Wall  process_group.c && ./a.out  
child process PID:7067
group ID is 7066
group ID is 7066
group ID is 7066

haha  I‘m father!
parent process ID 7066
group ID 7066
[email protected]:~/linux_c/进程间关系$

修改子进程、父进程的组ID

[email protected]:~/linux_c/进程间关系$ cat process_group.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
	pid_t pid;
	pid = fork();
	if(pid < 0)
	{
		perror("fork");
		exit(1);
	}
	else if(pid == 0)
	{
		printf("child process PID:%d\n",getpid());
		printf("group ID is %d\n",getpgrp());
		printf("group ID is %d\n",getpgid(0));
		printf("group ID is %d\n",getpgid(getpid()));
		exit(1);	//终止子进程运行
	}
	sleep(1);
	printf("\n\n");
	printf("haha  I‘m father!\n");
	printf("parent process ID %d\n",getpid());
	printf("group ID %d\n",getpgrp());

	return 0;
}
[email protected]:~/linux_c/进程间关系$ gcc -Wall  set_pgid.c && ./a.out  
child process PID is 7360
child process GID is 7359
chaning for child GID,plase wait ....
parent process PID is 7359
parent of parent process ID is 6468
parent process GID is 7359
Group ID of parent changed to 6468
child process GID is 7360
[email protected]:~/linux_c/进程间关系$

会话组

SID相同代表同一个会话
[email protected]:~/linux_c/进程间关系# cat |cat &
[email protected]:~/linux_c/进程间关系# ps ajx | grep 4759
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
  4756   4759   4759   4759 pts/8      6040 Ss    1000   0:00 -bash
  4759   4780   4780   4759 pts/8      6040 S        0   0:00 sudo -s
  4780   4781   4781   4759 pts/8      6040 S        0   0:00 /bin/bash
  4781   6032   6032   4759 pts/8      6040 T        0   0:00 cat
  4781   6033   6032   4759 pts/8      6040 T        0   0:00 cat
  4781   6040   6040   4759 pts/8      6040 R+       0   0:00 ps ajx
  4781   6041   6040   4759 pts/8      6040 S+       0   0:00 grep --color=auto 4759
[email protected]:~/linux_c/进程间关系# 

退出这个终端再去查原有会话全部结束
[email protected]:exit
[email protected]:~/linux_c/信号$ ps ajx | grep 4759
  5048   6063   6062   5048 pts/9      6062 S+    1000   0:00 grep --color=auto 4759
[email protected]:~/linux_c/信号$

设置一个会话脱离控制终端

pid_t setsid(void)

1.调用进程不能是进程组组长,该进程变成新会话首进程(session header)

2.该进程成为一个新进程组的组长进程。

3.需有root权限(ubuntu不需要)

4.新会话丢弃原有的控制终端,该会话没有控制终端

5.该调用进程是组长进程则出错返回

6.建立新会话时先调用fork, 父进程终止子进程调用

pid_t getsid(pid_t pid)

pid为0表示察看当前进程session ID

ps ajx命令查看系统中的进程。

参数a表示不仅列当前用户的进程也列出所有其他用户的进程

参数x表示不仅列有控制终端的进程也列出所有无控制终端的进程

参数j表示列出与作业控制相关的信息。

组长进程不能成为新会话首进程新会话首进程必定会成为组长进程。

生成一个新的会话

[email protected]:~/linux_c/进程间关系$ cat setsid.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
	pid_t pid;
	pid = fork();
	if(pid == -1)
	{
		perror("fork");
		exit(1);
	}
	if(pid == 0)
	{
		printf("child process id is %d\n",getpid());
		printf("group od of child is %d\n",getpgid(0));
		printf("session of child  is %d\n",getsid(0));
		sleep(10);
		int ret = setsid();
		if(ret == -1)
		{
			perror("setsid");
			exit(2);
		}
		printf("child process id is %d\n",getpid());
		printf("group od of child is %d\n",getpgid(0));
		printf("session of child  is %d\n",getsid(0));
		sleep(20);
		exit(0);

	}
	return 0;
}
[email protected]:~/linux_c/进程间关系$ 

编译运行
[email protected]:~/linux_c/进程间关系$ gcc setsid.c  && ./a.out 
child process id is 6308
group od of child is 6307
session of child  is 6128
[email protected]:~/linux_c/进程间关系$ child process id is 6308
group od of child is 6308
session of child  is 6308

[email protected]:~/linux_c/进程间关系$ 

[email protected]:~/linux_c/进程间关系$ ps aux | grep a.out
chunli     6308  0.0  0.0   4356    84 pts/8    S    21:02   0:00 ./a.out
chunli     6310  0.0  0.0  21312   940 pts/9    S+   21:02   0:00 grep --color=auto a.out

[email protected]:~/linux_c/进程间关系$ ps aux | grep a.out
chunli     6308  0.0  0.0   4356    84 ?        Ss   21:02   0:00 ./a.out
chunli     6312  0.0  0.0  21312   920 pts/9    S+   21:02   0:00 grep --color=auto a.out
[email protected]:~/linux_c/进程间关系$

守护进程

概念

Daemon(精灵)进程,是Linux中的后台服务进程,生存期较长的进程通常独立于控制终

端并且周期性地执行某种任务或等待处理某些发生的事件。

模型

守护进程编程步骤

1. 创建子进程父进程退出

所有工作在子进程中进行

  形式上脱离了控制终端

2. 在子进程中创建新会话

  setsid()函数

  使子进程完全独立出来脱离控制

3. 改变当前目录为根目录

  chdir()函数

  防止占用可卸载的文件系统

  也可以换成其它路径

4. 重设文件权限掩码

  umask()函数

  防止继承的文件创建屏蔽字拒绝某些权限

  增加守护进程灵活性

5. 关闭文件描述符

  继承的打开文件不会用到浪费系统资源无法卸载

6. 开始执行守护进程核心工作

7. 守护进程退出处理

守护进程模板

[email protected]:~/linux_c/进程间关系$ cat daemon.c 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
void daemonize()
{
	pid_t pid;
	pid = fork();
	if(pid == -1)
	{
		perror("fork");
		exit(2);
	}
	else if(pid > 0)
	{
		exit(2);
	}
	else
	{
		setsid();	//新的会话
		if(chdir("/") == -1 ) //改变目录
		{
			perror("chdir");
			exit(1);
		}
		umask(0);	//设置umask
		close(0);	//关闭文件描述符
		open("/dev/null",O_RDWR);
		dup2(0,1);	//关闭11指向0
		dup2(0,2);	//关闭22指向0
	}
}

int main()
{
	daemonize();
	while(1)
	{
		sleep(1);
	}
	return 0;
}

关闭当前窗口再开一个ssh可以看出 a.out 没有终端
[email protected]:~/linux_c/进程间关系$ gcc daemon.c  && ./a.out 
[email protected]:~/linux_c/进程间关系$ gcc daemon.c  && ./a.out 
[email protected]:~/linux_c/进程间关系$ ps aux | tail
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
chunli     6172  0.0  0.4  97588  4400 ?        S    20:53   0:00 sshd: [email protected]/9
chunli     6173  0.0  0.5  29600  5160 pts/9    Ss+  20:53   0:00 -bash
root       6322  0.0  0.0      0     0 ?        S    21:14   0:00 [kworker/u256:0]
root       6326  0.0  0.0      0     0 ?        S    21:22   0:00 [kworker/u256:1]
chunli     6327  0.2  0.9  65740  9088 pts/10   S+   21:25   0:01 vi daemon.c
root       6328  0.0  0.0      0     0 ?        S    21:31   0:00 [kworker/u256:2]
chunli     6422  0.0  0.0   4224    84 ?        Ss   21:35   0:00 ./a.out
chunli     6430  0.0  0.0   4224    84 ?        Ss   21:35   0:00 ./a.out
chunli     6431  0.0  0.3  44432  3252 pts/8    R+   21:35   0:00 ps aux
chunli     6432  0.0  0.0  14584   692 pts/8    S+   21:35   0:00 tail
[email protected]:~/linux_c/进程间关系$

获取当前系统时间

[email protected]:~/linux_c/进程间关系$ cat time.c 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
	time_t t;
	char buf[1024];
	time(&t);
	ctime_r(&t,buf);
	printf("%s",buf);
	return 0;
}

[email protected]:~/linux_c/进程间关系$ gcc time.c  && ./a.out 
Mon Aug 15 21:54:39 2016
[email protected]:~/linux_c/进程间关系$
时间: 2024-08-03 08:59:04

Linux系统开发7 进程关系,守护进程的相关文章

Linux系统编程——特殊进程之守护进程

什么是守护进程? 守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件. 守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示.由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都

Linux中 终端、作业控制与守护进程

1. 进程组 每个进程除了有一个进程 ID之外,还属于一个进程组.进程组是一个或多个进程的集合. 通常,它们与同一作业相关联,可以接收来自同一终端的各种信号. 每个进程组有一个唯 一的进程组ID.每个进程组都可以有一个组长进程.组长进程的标识是,其进程组 ID等于 其进程ID. 组长进程可以创建一个进程组,创建该组中的进程,然后终止. 只要在某个进程组中一个 进程存在,则该进程组就存在,这与其组长进程是否终止无关. 2.作业 Shell分前后台来控制的不是进程而是 作业(Job)或者进程组( P

Linux进程学习(孤儿进程和守护进程)

孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程如果一个子进程的父进程先于子进程 结束, 子进程就成为一个孤儿进程,它由 init 进程收养,成为 init 进程的子进程.2.那么如何让一个进程变为一个孤儿进程呢?我们可以先创建一个进程,然后杀死其父进程,则其就变成了孤儿进程.pid =  fork();if(pid > 0) {         

Linux进程学习 - 孤儿进程和守护进程

孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程如果一个子进程的父进程先于子进程 结束, 子进程就成为一个孤儿进程,它由 init 进程收养,成为 init 进程的子进程.2.那么如何让一个进程变为一个孤儿进程呢?我们可以先创建一个进程,然后杀死其父进程,则其就变成了孤儿进程.pid =  fork();if(pid > 0) {         

Linux 系统开发5 进程间通信 pipe() fifo() mmap()

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] Linux 系统开发5 进程间通信 pipe() fifo() mmap() pipe()管道通信介绍 pipe()父子进程通信案例 pipe()使用管道有一些限制 pipe()管道缓存区大小 pipe() 读端非阻塞管道 fifo()管道文件 fifo()写端/读端程序 管道文件在磁盘上的大小是0 mmap()将文件映射到内存 mmap()写端/读端程序 mmap()传输结构体数据,删除临时文件 pipe

Linux系统开发 2 文件IO open() close() read() write() perror() lseek() fcntl() ioctl()

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] 大纲 Linux系统开发 man 文档的使用 文件IO open() 创建文件,指定权限位 open() 接收参数 创建文件 open() 传两个参数 第三个参数从内存取垃圾值 write()函数 向文件写数据 write()函数的覆盖操作 open()函数文件的追加 open() 创建文件,如果文件已经存在,就报错 测试一个程序最多能创建1021个文件,3个STDIN STDOUT STDERR已经存在了

Linux系统开发8 线程

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <大纲> Linux系统开发8 线程 线程概念 浏览器 火狐多线程,谷歌多进程比较: 查看某一个进程有哪些线程 线程间共享资源 线程间非共享资源 线程优缺点 安装完整的manpage文档 pthread_create()创建线程 pthread_self() 获取线程自己的ID 线程创建程序演示: 指定libpthread.so库编译链接 演示:进程结束,线程也会立即结束 pthread_exit() 调用

python并发编程-进程理论-进程方法-守护进程-互斥锁-01

操作系统发展史(主要的几个阶段) 初始系统 1946年第一台计算机诞生,采用手工操作的方式(用穿孔卡片操作) 同一个房间同一时刻只能运行一个程序,效率极低(操作一两个小时,CPU一两秒可能就运算完了) 联机批处理系统 脱机批处理系统 多道程序系统 1.空间上的复用 ? 多个程序公用一套计算机硬件 2.时间上的复用 ? 切换+保存状态 ? 保存状态:保存当前的运行状态,下次接着该状态继续执行 ? 切换的两种情况 ? (1) 当一个程序遇到 I/O 操作(不需要使用CPU),操作系统会剥夺该程序的C

Linux系统开发6 信号

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] <大纲> Linux系统开发6 信号 linux系统有64种信号 signal man文档 终端按键信号 ctrl +c SIGIN ctrl +z SIGTSTP ctrl +\ SIGQUIT 硬件产生信号 浮点数例外信号  访问非法内存 kill()函数 信号与权限 kill()函数的pid 与返回值 信号产生原因 raise() 信号 abort() 信号 alarm() 信号 收到信号的默认操作