12.多进程程序的操作
12.多进程程序的操作
创建进程:
创建进程的函数是fork():
我们来看看帮助文件:man 2 fork:
AME
fork - create a child process
SYNOPSIS
#include <unistd.h>
pid_t fork(void);
DESCRIPTION
fork() creates a new process by duplicating the calling process. The new process,
referred to as the child, is an exact duplicate of the calling process, referred
to as the parent, except for the following points:
* The child has its own unique process ID, and this PID does not match the ID of
any existing process group (setpgid(2)).
* The child's parent process ID is the same as the parent's process ID.
* The child does not inherit its parent's memory locks (mlock(2), mlockall(2)).
* Process resource utilizations (getrusage(2)) and CPU time counters (times(2))
are reset to zero in the child.
* The child's set of pending signals is initially empty (sigpending(2)).
* The child does not inherit semaphore adjustments from its parent (semop(2)).
* The child does not inherit record locks from its parent (fcntl(2)).
* The child does not inherit timers from its parent (setitimer(2), alarm(2),
timer_create(2)).
* The child does not inherit outstanding asynchronous I/O operations from its
parent (aio_read(3), aio_write(3)), nor does it inherit any asynchronous I/O
contexts from its parent (seeio_setup(2)).
The process attributes in the preceding list are all specified in POSIX.1-2001.
The parent and child also differ with respect to the following Linux-specific pro-
cess attributes:
* The child does not inherit directory change notifications (dnotify) from its
parent (see the description of F_NOTIFY in fcntl(2)).
* The prctl(2) PR_SET_PDEATHSIG setting is reset so that the child does not
receive a signal when its parent terminates.
* Memory mappings that have been marked with the madvise(2) MADV_DONTFORK flag
are not inherited across a fork().
* The termination signal of the child is always SIGCHLD (see clone(2)).
Note the following further points:
* The child process is created with a single thread — the one that called fork().
The entire virtual address space of the parent is replicated in the child,
including the states of mutexes, condition variables, and other pthreads
objects; the use of pthread_atfork(3) may be helpful for dealing with problems
that this can cause.
* The child inherits copies of the parent's set of open file descriptors. Each
file descriptor in the child refers to the same open file description (see
open(2)) as the corresponding file descriptor in the parent. This means that
the two descriptors share open file status flags, current file offset, and sig-
nal-driven I/O attributes (see the description of F_SETOWN and F_SETSIG in
fcntl(2)).
* The child inherits copies of the parent's set of open message queue descriptors
(see mq_overview(7)). Each descriptor in the child refers to the same open
message queue description as the corresponding descriptor in the parent. This
means that the two descriptors share the same flags (mq_flags).
* The child inherits copies of the parent's set of open directory streams (see
opendir(3)). POSIX.1-2001 says that the corresponding directory streams in the
parent and child may share the directory stream positioning; on Linux/glibc
they do not.
RETURN VALUE
On success, the PID of the child process is returned in the parent, and 0 is
returned in the child. On failure, -1 is returned in the parent, no child process
is created, and errno is set appropriately.
ERRORS
EAGAIN fork() cannot allocate sufficient memory to copy the parent's page tables
and allocate a task structure for the child.
EAGAIN It was not possible to create a new process because the caller's
RLIMIT_NPROC resource limit was encountered. To exceed this limit, the
process must have either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capabil-
ity.
ENOMEM fork() failed to allocate the necessary kernel structures because memory is
tight.
CONFORMING TO
SVr4, 4.3BSD, POSIX.1-2001.
NOTES
Under Linux, fork() is implemented using copy-on-write pages, so the only penalty
that it incurs is the time and memory required to duplicate the parent's page
tables, and to create a unique task structure for the child.
Since version 2.3.3, rather than invoking the kernel's fork() system call, the
glibc fork() wrapper that is provided as part of the NPTL threading implementation
invokes clone(2) with flags that provide the same effect as the traditional system
call. The glibc wrapper invokes any fork handlers that have been established
using pthread_atfork(3).
EXAMPLE
See pipe(2) and wait(2).
SEE ALSO
clone(2), execve(2), setrlimit(2), unshare(2), vfork(2), wait(2), daemon(3), capa-
bilities(7), credentials(7)
COLOPHON
This page is part of release 3.22 of the Linux man-pages project. A description
of the project, and information about reporting bugs, can be found at
http://www.kernel.org/doc/man-pages/.
创建一个进程的函数是fork()。函数的原型:
pid_t fork(void);
该函数的功能是创建一个子进程。需要的头文件:unistd.h。
该函数的返回值:在成功的情况下返回两个:
-
在父进程中返回子进程的PID。
-
在子进程中返回的是0.
在失败的情况下:返回的是-1.
该函数是没有参数的。
实例:multiprocess.c:
#include <unistd.h>
#include <stdio.h>
void main(){
fork();
printf("process is me \n");
exit(0);
}
运行的结果:
我们从运行的结果看到,程序运行一次,printf打印了两次信息。这就是fork函数产生的。当一个进程调用了fork函数后,会产生一个子进程,子进程开始运行的位置是fork函数之后的第一行开始运行。该子进程的参数是复制父进程的初始参数的参数。
我们从上面知道,进程调用fork函数会返回两个值:父进程返回子进程的PID,子进程返回0.由此我们可以根据他们返回值的不同,可以使他们去实现不同的功能。
我们来看下面的例子:
muitiprocess1.c:
#include <unistd.h>
#include <stdio.h>
void main(){
pid_t pid;
pid = fork();
if(pid > 0){
printf("hello father process!\n");
exit(0);
}
else{
printf("hello child process!\n");
exit(0);
}
}
运行的结果:
这就实现了父子进程做不同的事情。
另外一个创建进程的函数是:vfork:
查看帮助文档:man 2 vfork:
NAME
vfork - create a child process and block parent
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
vfork(): _BSD_SOURCE || _XOPEN_SOURCE >= 500
DESCRIPTION
Standard Description
(From POSIX.1) The vfork() function has the same effect as fork(2), except that
the behavior is undefined if the process created by vfork() either modifies any
data other than a variable of type pid_t used to store the return value from
vfork(), or returns from the function in which vfork() was called, or calls any
other function before successfully calling _exit(2) or one of the exec(3) family
of functions.
Linux Description
vfork(), just like fork(2), creates a child process of the calling process. For
details and return value and errors, see fork(2).
vfork() is a special case of clone(2). It is used to create new processes without
copying the page tables of the parent process. It may be useful in performance-
sensitive applications where a child will be created which then immediately issues
an execve(2).
vfork() differs from fork(2) in that the parent is suspended until the child ter-
minates (either normally, by calling _exit(2), or abnormally, after delivery of a
fatal signal), or it makes a call to execve(2). Until that point, the child
shares all memory with its parent, including the stack. The child must not return
from the current function or call exit(3), but may call _exit(2).
Signal handlers are inherited, but not shared. Signals to the parent arrive after
the child releases the parent's memory (i.e., after the child terminates or calls
execve(2)).
Historic Description
Under Linux, fork(2) is implemented using copy-on-write pages, so the only penalty
incurred by fork(2) is the time and memory required to duplicate the parent's page
tables, and to create a unique task structure for the child. However, in the bad
old days a fork(2) would require making a complete copy of the caller's data
space, often needlessly, since usually immediately afterwards an exec(3) is done.
Thus, for greater efficiency, BSD introduced the vfork() system call, which did
not fully copy the address space of the parent process, but borrowed the parent's
memory and thread of control until a call to execve(2) or an exit occurred. The
parent process was suspended while the child was using its resources. The use of
vfork() was tricky: for example, not modifying data in the parent process depended
on knowing which variables are held in a register.
CONFORMING TO
4.3BSD, POSIX.1-2001. POSIX.1-2008 removes the specification of vfork(). The
requirements put on vfork() by the standards are weaker than those put on fork(2),
so an implementation where the two are synonymous is compliant. In particular,
the programmer cannot rely on the parent remaining blocked until the child either
terminates or calls execve(2), and cannot rely on any specific behavior with
respect to shared memory.
NOTES
Linux Notes
Fork handlers established using pthread_atfork(3) are not called when a multi-
threaded program employing the NPTL threading library calls vfork(). Fork han-
dlers are called in this case in a program using the LinuxThreads threading
library. (See pthreads(7) for a description of Linux threading libraries.)
History
The vfork() system call appeared in 3.0BSD. In 4.4BSD it was made synonymous to
fork(2) but NetBSD introduced it again, cf. http://www.netbsd.org/Documenta-
tion/kernel/vfork.html . In Linux, it has been equivalent to fork(2) until
2.2.0-pre6 or so. Since 2.2.0-pre9 (on i386, somewhat later on other architec-
tures) it is an independent system call. Support was added in glibc 2.0.112.
BUGS
It is rather unfortunate that Linux revived this specter from the past. The BSD
man page states: "This system call will be eliminated when proper system sharing
mechanisms are implemented. Users should not depend on the memory sharing seman-
tics of vfork() as it will, in that case, be made synonymous to fork(2)."
Details of the signal handling are obscure and differ between systems. The BSD
man page states: "To avoid a possible deadlock situation, processes that are chil-
dren in the middle of a vfork() are never sent SIGTTOU or SIGTTIN signals; rather,
output or ioctls are allowed and input attempts result in an end-of-file indica-
tion."
SEE ALSO
clone(2), execve(2), fork(2), unshare(2), wait(2)
COLOPHON
This page is part of release 3.22 of the Linux man-pages project. A description
of the project, and information about reporting bugs, can be found at
http://www.kernel.org/doc/man-pages/.
Vfork的函数的原型是:
pid_t vfork(void);
该函数的功能是创建一个子进程,并阻塞父进程。这就决定了在调用vfork函数创建子进程的时候,先执行子进程,后再执行父进程。而上面的fork函数则次序是不一定谁先执行。
需要的头文件:
<sys/types.h> <unistd.h>
返回值是:成功:
-
在父进程中返回子进程的PID。
-
在子进程中返回的是0.
失败则返回-1.
没有参数。
实例:multiprocess2.c:
#include <unistd.h>
#include <stdio.h>
void main(){
pid_t pid;
pid = vfork();
if(pid > 0){
printf("hello father process!\n");
exit(0);
}
else{
printf("hello child process!\n");
exit(0);
}
}
运行的结果:
这就是vfork的一个例子,我们看到结果是先执行子进程后执行父进程。这是fork和vfork的一个不同点。还有一个不同点事:fork的父子进程使用不同但是初始条件相同的变量环境,即是栈,就是他们的各自的变量环境,初始条件是相同的。而vfork则是父子进程共用一个变量环境。
Count.c:
#include <unistd.h>
#include <stdio.h>
void main(){
pid_t pid;
int count = 0;
pid = fork();
count = count + 1;
printf("count is %d \n",count);
exit(0);
}
运行的结果:
实例:vcount.c:
#include <unistd.h>
#include <stdio.h>
void main(){
pid_t pid;
int count = 0;
pid = vfork();
count = count + 1;
printf("count is %d \n",count);
exit(0);
}
程序运行的结果:
这跟我们fork和vfork的区别。
进程退出:
帮助文档的信息:man 2 exit:
NAME
_exit, _Exit - terminate the calling process
SYNOPSIS
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void _Exit(int status);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
_Exit(): _XOPEN_SOURCE >= 600 || _ISOC99_SOURCE; or cc -std=c99
DESCRIPTION
The function _exit() terminates the calling process "immediately". Any open file
descriptors belonging to the process are closed; any children of the process are
inherited by process 1, init, and the process's parent is sent a SIGCHLD signal.
The value status is returned to the parent process as the process's exit status,
and can be collected using one of the wait(2) family of calls.
The function _Exit() is equivalent to _exit().
RETURN VALUE
These functions do not return.
CONFORMING TO
SVr4, POSIX.1-2001, 4.3BSD. The function _Exit() was introduced by C99.
NOTES
For a discussion on the effects of an exit, the transmission of exit status, zom-
bie processes, signals sent, etc., see exit(3).
The function _exit() is like exit(3), but does not call any functions registered
with atexit(3) or on_exit(3). Whether it flushes standard I/O buffers and removes
temporary files created with tmpfile(3) is implementation-dependent. On the other
hand, _exit() does close open file descriptors, and this may cause an unknown
delay, waiting for pending output to finish. If the delay is undesired, it may be
useful to call functions like tcflush(3) before calling _exit(). Whether any
pending I/O is canceled, and which pending I/O may be canceled upon _exit(), is
implementation-dependent.
In glibc up to version 2.3, the _exit() wrapper function invoked the kernel system
call of the same name. Since glibc 2.3, the wrapper function invokes
exit_group(2), in order to terminate all of the threads in a process.
SEE ALSO
execve(2), exit_group(2), fork(2), kill(2), wait(2), wait4(2), waitpid(2),
atexit(3), exit(3), on_exit(3), termios(3)
COLOPHON
This page is part of release 3.22 of the Linux man-pages project. A description
of the project, and information about reporting bugs, can be found at
http://www.kernel.org/doc/man-pages/.
在父进程中可以使用return 和exit来退出进程:
成功:return 0 或 exit(0).如果异常则return 1 或exit(1).
return是语言级别的,不管你用不用都是存在的,它表示了调用堆栈的返回;而exit是操作系统中系统调用级别的,它表示了一个进程的结束。当然如果是mian函数中return(0)跟exit(0)是等效的。
Multiprocess1.c:
#include <unistd.h>
#include <stdio.h>
void main(){
pid_t pid;
pid = fork();
if(pid > 0){
printf("hello father process!\n");
return 0;
//exit(0);
}
else{
printf("hello child process!\n");
exit(0);
}
}
运行的结果:
上面的程序中使用了return,正常退出父进程。
Multiprocess2.c:
#include <unistd.h>
#include <stdio.h>
void main(){
pid_t pid;
pid = fork();
if(pid > 0){
printf("hello father process!\n");
return 0;
//exit(0);
}
else{
printf("hello child process!\n");
return 0;
//exit(0);
}
}
运行的结果:
跟父进程等效。
线程等待:
Man的信息:man 2 wait:
NAME
wait, waitpid, waitid - wait for process to change state
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
waitid(): _SVID_SOURCE || _XOPEN_SOURCE
DESCRIPTION
All of these system calls are used to wait for state changes in a child of the
calling process, and obtain information about the child whose state has
changed. A state change is considered to be: the child terminated; the child
was stopped by a signal; or the child was resumed by a signal. In the case of
a terminated child, performing a wait allows the system to release the
resources associated with the child; if a wait is not performed, then the ter-
minated child remains in a "zombie" state (see NOTES below).
If a child has already changed state, then these calls return immediately.
Otherwise they block until either a child changes state or a signal handler
interrupts the call (assuming that system calls are not automatically restarted
using the SA_RESTART flag of sigaction(2)). In the remainder of this page, a
child whose state has changed and which has not yet been waited upon by one of
these system calls is termed waitable.
wait() and waitpid()
The wait() system call suspends execution of the calling process until one of
its children terminates. The call wait(&status) is equivalent to:
waitpid(-1, &status, 0);
The waitpid() system call suspends execution of the calling process until a
child specified by pid argument has changed state. By default, waitpid() waits
only for terminated children, but this behavior is modifiable via the options
argument, as described below.
The value of pid can be:
< -1 meaning wait for any child process whose process group ID is equal to
the absolute value of pid.
-1 meaning wait for any child process.
0 meaning wait for any child process whose process group ID is equal to
that of the calling process.
> 0 meaning wait for the child whose process ID is equal to the value of
pid.
The value of options is an OR of zero or more of the following constants:
WNOHANG return immediately if no child has exited.
WUNTRACED also return if a child has stopped (but not traced via ptrace(2)).
Status for traced children which have stopped is provided even if
this option is not specified.
WCONTINUED (since Linux 2.6.10)
also return if a stopped child has been resumed by delivery of SIG-
CONT.
(For Linux-only options, see below.)
If status is not NULL, wait() and waitpid() store status information in the int
to which it points. This integer can be inspected with the following macros
(which take the integer itself as an argument, not a pointer to it, as is done
in wait() and waitpid()!):
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling
exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)
returns the exit status of the child. This consists of the least sig-
nificant 8 bits of the status argument that the child specified in a
call to exit(3) or _exit(2) or as the argument for a return statement in
main(). This macro should only be employed if WIFEXITED returned true.
WIFSIGNALED(status)
returns true if the child process was terminated by a signal.
WTERMSIG(status)
returns the number of the signal that caused the child process to termi-
nate. This macro should only be employed if WIFSIGNALED returned true.
WCOREDUMP(status)
returns true if the child produced a core dump. This macro should only
be employed if WIFSIGNALED returned true. This macro is not specified
in POSIX.1-2001 and is not available on some Unix implementations (e.g.,
AIX, SunOS). Only use this enclosed in #ifdef WCOREDUMP ... #endif.
WIFSTOPPED(status)
returns true if the child process was stopped by delivery of a signal;
this is only possible if the call was done using WUNTRACED or when the
child is being traced (see ptrace(2)).
WSTOPSIG(status)
returns the number of the signal which caused the child to stop. This
macro should only be employed if WIFSTOPPED returned true.
WIFCONTINUED(status)
(since Linux 2.6.10) returns true if the child process was resumed by
delivery of SIGCONT.
waitid()
The waitid() system call (available since Linux 2.6.9) provides more precise
control over which child state changes to wait for.
The idtype and id arguments select the child(ren) to wait for, as follows:
idtype == P_PID
Wait for the child whose process ID matches id.
idtype == P_PGID
Wait for any child whose process group ID matches id.
idtype == P_ALL
Wait for any child; id is ignored.
The child state changes to wait for are specified by ORing one or more of the
following flags in options:
WEXITED Wait for children that have terminated.
WSTOPPED Wait for children that have been stopped by delivery of a signal.
WCONTINUED Wait for (previously stopped) children that have been resumed by
delivery of SIGCONT.
The following flags may additionally be ORed in options:
WNOHANG As for waitpid().
WNOWAIT Leave the child in a waitable state; a later wait call can be used
to again retrieve the child status information.
Upon successful return, waitid() fills in the following fields of the siginfo_t
structure pointed to by infop:
si_pid The process ID of the child.
si_uid The real user ID of the child. (This field is not set on most
other implementations.)
si_signo Always set to SIGCHLD.
si_status Either the exit status of the child, as given to _exit(2) (or
exit(3)), or the signal that caused the child to terminate, stop,
or continue. The si_code field can be used to determine how to
interpret this field.
si_code Set to one of: CLD_EXITED (child called _exit(2)); CLD_KILLED
(child killed by signal); CLD_DUMPED (child killed by signal, and
dumped core); CLD_STOPPED (child stopped by signal); CLD_TRAPPED
(traced child has trapped); or CLD_CONTINUED (child continued by
SIGCONT).
If WNOHANG was specified in options and there were no children in a waitable
state, then waitid() returns 0 immediately and the state of the siginfo_t
structure pointed to by infop is unspecified. To distinguish this case from
that where a child was in a waitable state, zero out the si_pid field before
the call and check for a non-zero value in this field after the call returns.
RETURN VALUE
wait(): on success, returns the process ID of the terminated child; on error,
-1 is returned.
waitpid(): on success, returns the process ID of the child whose state has
changed; if WNOHANG was specified and one or more child(ren) specified by pid
exist, but have not yet changed state, then 0 is returned. On error, -1 is
returned.
waitid(): returns 0 on success or if WNOHANG was specified and no child(ren)
specified by id has yet changed state; on error, -1 is returned. Each of these
calls sets errno to an appropriate value in the case of an error.
ERRORS
ECHILD (for wait()) The calling process does not have any unwaited-for chil-
dren.
ECHILD (for waitpid() or waitid()) The process specified by pid (waitpid()) or
idtype and id (waitid()) does not exist or is not a child of the calling
process. (This can happen for one's own child if the action for SIGCHLD
is set to SIG_IGN. See also the Linux Notes section about threads.)
EINTR WNOHANG was not set and an unblocked signal or a SIGCHLD was caught; see
signal(7).
EINVAL The options argument was invalid.
CONFORMING TO
SVr4, 4.3BSD, POSIX.1-2001.
NOTES
A child that terminates, but has not been waited for becomes a "zombie". The
kernel maintains a minimal set of information about the zombie process (PID,
termination status, resource usage information) in order to allow the parent to
later perform a wait to obtain information about the child. As long as a zom-
bie is not removed from the system via a wait, it will consume a slot in the
kernel process table, and if this table fills, it will not be possible to cre-
ate further processes. If a parent process terminates, then its "zombie" chil-
dren (if any) are adopted by init(8), which automatically performs a wait to
remove the zombies.
POSIX.1-2001 specifies that if the disposition of SIGCHLD is set to SIG_IGN or
the SA_NOCLDWAIT flag is set for SIGCHLD (see sigaction(2)), then children that
terminate do not become zombies and a call to wait() or waitpid() will block
until all children have terminated, and then fail with errno set to ECHILD.
(The original POSIX standard left the behavior of setting SIGCHLD to SIG_IGN
unspecified. Note that even though the default disposition of SIGCHLD is
"ignore", explicitly setting the disposition to SIG_IGN results in different
treatment of zombie process children.) Linux 2.6 conforms to this specifica-
tion. However, Linux 2.4 (and earlier) does not: if a wait() or waitpid() call
is made while SIGCHLD is being ignored, the call behaves just as though SIGCHLD
were not being ignored, that is, the call blocks until the next child termi-
nates and then returns the process ID and status of that child.
Linux Notes
In the Linux kernel, a kernel-scheduled thread is not a distinct construct from
a process. Instead, a thread is simply a process that is created using the
Linux-unique clone(2) system call; other routines such as the portable
pthread_create(3) call are implemented using clone(2). Before Linux 2.4, a
thread was just a special case of a process, and as a consequence one thread
could not wait on the children of another thread, even when the latter belongs
to the same thread group. However, POSIX prescribes such functionality, and
since Linux 2.4 a thread can, and by default will, wait on children of other
threads in the same thread group.
The following Linux-specific options are for use with children created using
clone(2); they cannot be used with waitid():
__WCLONE
Wait for "clone" children only. If omitted then wait for "non-clone"
children only. (A "clone" child is one which delivers no signal, or a
signal other than SIGCHLD to its parent upon termination.) This option
is ignored if __WALL is also specified.
__WALL (since Linux 2.4)
Wait for all children, regardless of type ("clone" or "non-clone").
__WNOTHREAD (since Linux 2.4)
Do not wait for children of other threads in the same thread group.
This was the default before Linux 2.4.
EXAMPLE
The following program demonstrates the use of fork(2) and waitpid(). The pro-
gram creates a child process. If no command-line argument is supplied to the
program, then the child suspends its execution using pause(2), to allow the
user to send signals to the child. Otherwise, if a command-line argument is
supplied, then the child exits immediately, using the integer supplied on the
command line as the exit status. The parent process executes a loop that moni-
tors the child using waitpid(), and uses the W*() macros described above to
analyze the wait status value.
The following shell session demonstrates the use of the program:
$ ./a.out &
Child PID is 32360
[1] 32359
$ kill -STOP 32360
stopped by signal 19
$ kill -CONT 32360
continued
$ kill -TERM 32360
killed by signal 15
[1]+ Done ./a.out
$
Program source
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}
SEE ALSO
_exit(2), clone(2), fork(2), kill(2), ptrace(2), sigaction(2), signal(2),
wait4(2), pthread_create(3), credentials(7), signal(7)
COLOPHON
This page is part of release 3.22 of the Linux man-pages project. A descrip-
tion of the project, and information about reporting bugs, can be found at
http://www.kernel.org/doc/man-pages/.
线程的等待函数的原型:
pid_t wait(int *status);
该函数的功能是挂起调用的进程,直到其子进程结束。
需要的头文件:
<sys/types.h><sys/wait.h>
该函数的返回值:成功则是返回等待期间执行的那个子进程的ID。
失败则是返回-1.
该函数有一个参数:记录子进程的退出状态。
实例:wait.c:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
void main(){
pid_t pid;
pid = fork();
if(pid > 0){
wait(NULL);
printf("hello father process!\n");
exit(0);
}
else{
printf("hello child process!\n");
exit(0);
}
}
运行结果:
程序执行:
程序执行的函数是以函数族的形式存在:
函数名execl:
查看帮助文档:man execl:
NAME
execl, execlp, execle, execv, execvp - execute a file
SYNOPSIS
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
DESCRIPTION
The exec() family of functions replaces the current process image with a new
process image. The functions described in this manual page are front-ends for
execve(2). (See the manual page for execve(2) for further details about the
replacement of the current process image.)
The initial argument for these functions is the pathname of a file which is to
be executed.
The const char *arg and subsequent ellipses in the execl(), execlp(), and exe-
cle() functions can be thought of as arg0, arg1, ..., argn. Together they
describe a list of one or more pointers to null-terminated strings that repre-
sent the argument list available to the executed program. The first argument,
by convention, should point to the filename associated with the file being exe-
cuted. The list of arguments must be terminated by a NULL pointer, and, since
these are variadic functions, this pointer must be cast (char *) NULL.
The execv() and execvp() functions provide an array of pointers to null-termi-
nated strings that represent the argument list available to the new program.
The first argument, by convention, should point to the filename associated with
the file being executed. The array of pointers must be terminated by a NULL
pointer.
The execle() function also specifies the environment of the executed process by
following the NULL pointer that terminates the list of arguments in the argu-
ment list or the pointer to the argv array with an additional argument. This
additional argument is an array of pointers to null-terminated strings and must
be terminated by a NULL pointer. The other functions take the environment for
the new process image from the external variable environ in the current pro-
cess.
Special semantics for execlp() and execvp()
The functions execlp() and execvp() will duplicate the actions of the shell in
searching for an executable file if the specified filename does not contain a
slash (/) character. The search path is the path specified in the environment
by the PATH variable. If this variable isn't specified, the default path
":/bin:/usr/bin" is used. In addition, certain errors are treated specially.
If permission is denied for a file (the attempted execve(2) failed with the
error EACCES), these functions will continue searching the rest of the search
path. If no other file is found, however, they will return with errno set to
EACCES.
If the header of a file isn't recognized (the attempted execve(2) failed with
the error ENOEXEC), these functions will execute the shell (/bin/sh) with the
path of the file as its first argument. (If this attempt fails, no further
searching is done.)
RETURN VALUE
If any of the exec() functions returns, an error will have occurred. The
return value is -1, and errno will be set to indicate the error.
ERRORS
All of these functions may fail and set errno for any of the errors specified
for the library function execve(2).
CONFORMING TO
POSIX.1-2001.
NOTES
On some other systems the default path (used when the environment does not con-
tain the variable PATH) has the current working directory listed after /bin and
/usr/bin, as an anti-Trojan-horse measure. Linux uses here the traditional
"current directory first" default path.
The behavior of execlp() and execvp() when errors occur while attempting to
execute the file is historic practice, but has not traditionally been docu-
mented and is not specified by the POSIX standard. BSD (and possibly other
systems) do an automatic sleep and retry if ETXTBSY is encountered. Linux
treats it as a hard error and returns immediately.
Traditionally, the functions execlp() and execvp() ignored all errors except
for the ones described above and ENOMEM and E2BIG, upon which they returned.
They now return if any error other than the ones described above occurs.
SEE ALSO
sh(1), execve(2), fork(2), ptrace(2), fexecve(3), environ(7)
COLOPHON
This page is part of release 3.22 of the Linux man-pages project. A descrip-
tion of the project, and information about reporting bugs, can be found at
http://www.kernel.org/doc/man-pages/.
该函数的一个原型:
int execl(const char *path, const char *arg, ...);
该函数的功能是运行可执行文件。
需要的头文件:<unistd.h>
返回值:成功不返回。
失败:-1
Pathname:可执行文件的路径。
arg:可执行文件需要的参数。以NULL来结束参数。
execl.c:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
void main(){
pid_t pid;
pid = fork();
if(pid > 0){
wait(NULL);
printf("hello father process!\n");
exit(0);
}
else{
execl("/bin/ls","ls","/home/forfish",NULL);
printf("hello child process!\n");
exit(0);
}
}
运行的结果:
可以看到他列出了和直接使用ls命令一个的效果。但是没有打印execl后面的打印信息。这是因为当调用execl的时候,他会覆盖掉原有的代码。也就是说,在该程序中,由于调用了execl,结果是子进程的代码被execl的/bin/ls的代码覆盖掉。注意不是产生新进程,只是覆盖。所以,子进程没有打印信息。
Fork与execl对比: