多进程编程
1、进程的创建
1.1 复制创建新的进程
fork();
#include <unistd.h>
pid_t fork(void);
参数:
- 无
返回值: 成功,子进程的id号,返回给父进程,0返回给子进程;
失败,返回-1给父进程,子进程不被创建
1.2替换创建新的进程
execl();家族函数
#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[]);
参数:
- 第一个参数,指向被执行的文件,
- 其余的参数以NULL作为结束标志。
返回值:成功不不返回参数,失败返回-1;
excev()家族函数
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
参数:
- 第一个参数,指向被执行的文件,
- 其余的参数以NULL作为结束标志。
返回值:成功不返回参数,失败返回-1
2、等待子进程的退出
wait;
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
参数:进程状态
返回值:成功,返回退出子进程的ID值;失败返回-1;
waitpid();
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
参数:
-
处理方式:
<-1:等待任意子进程,其进程ID为pid绝对值
-1:等待所有子进程
0:等待任意组ID等于调用进程
大于0:等待子进程ID等于pid的值
-
进程状态
-
选择值
返回值:成功返回0;失败返回-1;
3、进程间信号
信号处理函数signal
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数:
- signum: 指定信号
- handler:处理函数
返回值:成功,上一个信号值;失败,返回SIG_ERR
信号处理函数sigcation
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
参数:
- signum:指定信号
- 非空,赋予新的信号
- 非空,保存以前的信号
返回值:成功返回0;失败返回-1;
信号发送函数 kill();
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
参数:
- pid = 0;向组内所有进程发送信号
- pid = -1;向允许发送的所有线程发送,不包含初始进程
- pid < -1;向组内指定进程(-pid)发送信号
返回值:成功,返回0;失败,返回-1;
//信号实例
#include <stdio.h>
#include <signal.h>
void sig_handler(int signo);
int main(int argc, char *argv[])
{
//typedef void (*sighandler_t)(int);
//sighandler_t signal(int signum,
// sighandler_t handler);
//signal(2, sig_handler);
// 为指定信号注册信号处理函数
signal(SIGINT, sig_handler);
while(1);
return 0;
}
void sig_handler(int signo)
{
printf("hahahaha\n");
}
进程实例:
// 练习1:在父进程中为SIGINT信号注册处理函数,然后创建一个子进程,父子进程均进行无限循环,使用Ctrl+c组合键触发SIGINT信号,观察父子进程的执行情况
// 注意:子进程在创建时会copy当前父进程的信号处理方式
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void sig_handler(int signo);
int main(int argc, char *argv[])
{
pid_t pid;
struct sigaction act;//定义一个act访问sigaction结构体变量
//signal(SIGINT, SIG_IGN);
//signal(SIGINT, SIG_DFL);
//signal(SIGINT, sig_handler);
act.sa_handler = sig_handler;
//act.sa_handler = SIG_IGN;
//act.sa_handler = SIG_DFL;
sigaction(SIGINT, &act, NULL);
pid = fork();
while(1);
return 0;
}
void sig_handler(int signo)
{
switch(signo)
{
case SIGINT:
printf("signal SIGINT catched in process %d\n", getpid());
}
}
// 注意:本例使用信号异步处理僵尸进程
// 实现原理:当子进程退出时,会向父进程发送SIGCHLD信号,在父进程的SIGCHLD信号处理函数中调用wait函数,防止僵尸进程的产生
// 信号处理函数能够使用其形式参数接收触发该函数的信号值
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>
void sig_handler(int signo);
int main(int argc, char *argv[])
{
pid_t pid;
srand(time(NULL));
// sigaction
signal(SIGCHLD, sig_handler);
while(1)
{
pid = fork();
if(pid == 0)
{
printf("child process %d is running...\n", getpid());
sleep(rand()%3+1);
//return 0;
exit(0);
}
else if(pid > 0)
{
sleep(1);
}
}
return 0;
}
// 信号处理函数能够使用其形式参数接收触发该函数的信号值
void sig_handler(int signo)
{
if(signo == SIGCHLD)
{
printf("child process %d is exit!!!\n",
wait(NULL));
}
}
网友评论