码迷,mamicode.com
首页 > 系统相关 > 详细

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

时间:2016-08-15 22:32:42      阅读:552      评论:0      收藏:0      [点我收藏+]

标签:守护进程   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 参数所代表的文件描述词为一终端机。

不同终端显示不同终端的名字
chunli@ubuntu:~/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连接编译运行
chunli@ubuntu:~/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)
chunli@ubuntu:~/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!
 */
};



进程组

chunli@ubuntu:~/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;
}
chunli@ubuntu:~/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
chunli@ubuntu:~/linux_c/进程间关系$


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

chunli@ubuntu:~/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;
}
chunli@ubuntu:~/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
chunli@ubuntu:~/linux_c/进程间关系$




会话组

SID相同代表同一个会话
root@ubuntu:~/linux_c/进程间关系# cat |cat &
root@ubuntu:~/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
root@ubuntu:~/linux_c/进程间关系# 

退出这个终端再去查原有会话全部结束
root@ubuntu:exit
chunli@ubuntu:~/linux_c/信号$ ps ajx | grep 4759
  5048   6063   6062   5048 pts/9      6062 S+    1000   0:00 grep --color=auto 4759
chunli@ubuntu:~/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表示列出与作业控制相关的信息。

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





生成一个新的会话

chunli@ubuntu:~/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;
}
chunli@ubuntu:~/linux_c/进程间关系$ 

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

chunli@ubuntu:~/linux_c/进程间关系$ 


chunli@ubuntu:~/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

chunli@ubuntu:~/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
chunli@ubuntu:~/linux_c/进程间关系$





守护进程



 概念

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

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




模型

守护进程编程步骤

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

所有工作在子进程中进行

  形式上脱离了控制终端

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

  setsid()函数

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

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

  chdir()函数

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

  也可以换成其它路径

4. 重设文件权限掩码

  umask()函数

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

  增加守护进程灵活性

5. 关闭文件描述符

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

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

7. 守护进程退出处理



守护进程模板


chunli@ubuntu:~/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 没有终端
chunli@ubuntu:~/linux_c/进程间关系$ gcc daemon.c  && ./a.out 
chunli@ubuntu:~/linux_c/进程间关系$ gcc daemon.c  && ./a.out 
chunli@ubuntu:~/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: chunli@pts/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
chunli@ubuntu:~/linux_c/进程间关系$




获取当前系统时间

chunli@ubuntu:~/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;
}
	
chunli@ubuntu:~/linux_c/进程间关系$ gcc time.c  && ./a.out 
Mon Aug 15 21:54:39 2016
chunli@ubuntu:~/linux_c/进程间关系$






本文出自 “魂斗罗” 博客,谢绝转载!

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

标签:守护进程   linux系统开发7 进程关系   

原文地址:http://990487026.blog.51cto.com/10133282/1839014

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!