进程控制(二)

5 wait和waitpid函数

  当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。

5.1调用wait或waitpid的进程可能会:

    阻塞(如果其子进程都还在运行)

    带子进程的终止状态立即返回

    出错立即返回

5.2wait和waitpid的区别: 

    在一个子进程终止前, wait 使其调用者阻塞,而 waitpid 有一选择项,可使调用者不阻塞。

    waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的进程。

代码示例:

#include "ourhdr.h"
#include <sys/wait.h>

void pr_exit(int status)
{
	if (WIFEXITED(status))
		printf("normal termination, exit status = %d
",
				WEXITSTATUS(status));
	else if (WIFSIGNALED(status))
		printf("abnormal termination, signal number = %d%s
",
				WTERMSIG(status),
#ifdef	WCOREDUMP
				WCOREDUMP(status) ? " (core file generated)" : "");
#else
				"");
#endif
	else if (WIFSTOPPED(status))
		printf("child stopped, signal number = %d
",
				WSTOPSIG(status));
}

int main(void)
{
	pid_t	pid;
	int		status;

	if ((pid = fork()) < 0)
		err_sys("fork error");
	else if (pid == 0)				/* child */
		exit(7);

	if (wait(&status) != pid)		/* wait for child */
		err_sys("wait error");
	pr_exit(status);				/* and print its status */

	if ((pid = fork()) < 0)
		err_sys("fork error");
	else if (pid == 0)				/* child */
		abort();					/* generates SIGABRT */

	if (wait(&status) != pid)		/* wait for child */
		err_sys("wait error");
	pr_exit(status);				/* and print its status */

	if ((pid = fork()) < 0)
		err_sys("fork error");
	else if (pid == 0)				/* child */
		status /= 0;				/* divide by 0 generates SIGFPE */

	if (wait(&status) != pid)		/* wait for child */
		err_sys("wait error");
	pr_exit(status);				/* and print its status */

	exit(0);
}

  打印结果:

[root@rac1 fork]# gcc wait.c 
wait.c: In function ‘main’:
wait.c:48: warning: division by zero

[root@rac1 fork]# ./a.out 
normal termination, exit status = 7
abnormal termination, signal number = 6
abnormal termination, signal number = 8

 5.3如果一个进程要 f o r k一个子进程,但不要求它等待子进程终止,也不希望子进程处于僵死状态直到父进程终止,实现这一要求的诀窍是调用 f o r k两次。

代码示例:

#include "ourhdr.h"
#include <sys/wait.h>
#include <sys/types.h>

int
main(void)
{
	pid_t	pid;

	if ((pid = fork()) < 0) {
		err_sys("fork error");
	} else if (pid == 0) {		/* first child */
		if ((pid = fork()) < 0)
			err_sys("fork error");
		else if (pid > 0)
			exit(0);	/* parent from second fork == first child */

		/*
		 * We're the second child; our parent becomes init as soon
		 * as our real parent calls exit() in the statement above.
		 * Here's where we'd continue executing, knowing that when
		 * we're done, init will reap our status.
		 */
		sleep(2);
		printf("second child, parent pid = %d
", getppid());
		exit(0);
	}

	if (waitpid(pid, NULL, 0) != pid)	/* wait for first child */
		err_sys("waitpid error");

	/*
	 * We're the parent (the original process); we continue executing,
	 * knowing that we're not the parent of the second child.
	 */
	exit(0);
}

  

 打印结果:

[root@rac1 fork]# ./a.out 
[root@rac1 fork]# second child, parent pid = 1

  

6 wait3 和wait4函数

7 竞态条件

  当多个进程都企图对共享数据进行某种处理,而最后的结果又取决于进程运行的顺序时,则我们认为这发生了竞态条件

  在父、子进程的关系中,常常出现下述情况。在 f o r k之后,父、子进程都有一些事情要做。例如,父进程可能以子进程 I D更新日志文件中的一个记录,而子进程则可能要为父进程创建一个文件

 代码示例:

tellwait.h

#include <sys/types.h>
static int	pfd1[2], pfd2[2];

void TELL_WAIT(void)
{
	if (pipe(pfd1) < 0 || pipe(pfd2) < 0)
		err_sys("pipe error");
}

void TELL_PARENT (pid_t pid)
{
	if (write(pfd2[1], "c", 1) != 1)
		err_sys("write error");
}

void WAIT_PARENT(void)
{
	char	c;

	if (read(pfd1[0], &c, 1) != 1)
		err_sys("read error");

	if (c != 'p')
		err_quit("WAIT_PARENT: incorrect data");
}

void TELL_CHILD(pid_t pid)
{
	if (write(pfd1[1], "p", 1) != 1)
		err_sys("write error");
}

void WAIT_CHILD(void)
{
	char	c;

	if (read(pfd2[0], &c, 1) != 1)
		err_sys("read error");

	if (c != 'c')
		err_quit("WAIT_CHILD: incorrect data");
}

  tell.c

#include "ourhdr.h"

static void charatatime(char *);

int main(void)
{
	pid_t	pid;

	TELL_WAIT();

	if ((pid = fork()) < 0) {
		err_sys("fork error");
	} else if (pid == 0) {
		WAIT_PARENT();		/* parent goes first */
		charatatime("output from child
");
	} else {
		charatatime("output from parent
");
		TELL_CHILD(pid);
	}
	exit(0);
}

static void
charatatime(char *str)
{
	char	*ptr;
	int		c;

	setbuf(stdout, NULL);			/* set unbuffered */
	for (ptr = str; (c = *ptr++) != 0; )
		putc(c, stdout);
}

  运行结果:

[root@rac1 fork]# ./tell 
output from parent
[root@rac1 fork]# output from child

[root@rac1 fork]# 

  

 8 exec函数

    用f o r k函数创建子进程后,子进程往往要调用一种 e x e c函数以执行另一个程序。
    当进程调用一种 e x e c函数时,该进程完全由新程序代换,而新程序则从其 m a i n函数开始执行

#include <unistd.h>
int execl(const char * pathname, const char * arg0, ... /* (char *) 0 */);
int execv(const char * pathname, char *const  argv  [] );
int execle(const char * pathname, const char * arg0, .../* (char *)0, char *const  envp [] */);
int execve(const char * pathname, char *const  argv  [], char *const  envp  [] );
int execlp(const char * filename, const char * arg0, ... /* (char *) 0 */);
int execvp(const char * filename, char *const  argv  [] );
六个函数返回:若出错则为- 1,若成功则不返回

  

代码示例:

#include "ourhdr.h"
#include <sys/wait.h>

char	*env_init[] = { "USER=unknown", "PATH=/tmp", NULL };

int
main(void)
{
	pid_t	pid;

	if ((pid = fork()) < 0) {
		err_sys("fork error");
	} else if (pid == 0) {	/* specify pathname, specify environment */
		if (execle("/usr/local/bin/python", "python", "myarg1",
				"--", (char *)0, env_init) < 0)
			err_sys("execle error");
	}

	if (waitpid(pid, NULL, 0) < 0)
		err_sys("wait error");

	if ((pid = fork()) < 0) {
		err_sys("fork error");
	} else if (pid == 0) {	/* specify filename, inherit environment */
		if (execlp("python", "", "myarg2", (char *)0) < 0)
			err_sys("execlp error");
	}

	exit(0);
}

  

原文地址:https://www.cnblogs.com/huanhuanang/p/4440660.html