版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rikeyone/article/details/88977157
在前文《Linux – 进程控制》博客中,我曾提到过父子进程之间的同步有两种方法:分别是基于管道和信号实现。
为什么需要进程的同步,当我们创建一个新进程时,为了保证父子进程的运行按照我们预期的时序进行,所以需要加入同步机制。下面直接以代码示例来实现两种同步方式。
基于管道实现的进程同步
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "include/debug.h"
static int pfd1[2], pfd2[2];
void initialize(void)
{
if (pipe(pfd1) < 0 || pipe(pfd2) < 0)
err_exit("pipe error");
}
void wake_parent(void)
{
if (write(pfd2[1], "c", 1) != 1)
err_exit("write error");
}
void wait_parent(void)
{
char c;
if (read(pfd1[0], &c, 1) != 1)
err_exit("read error");
if (c != 'p')
err_exit("WAIT_PARENT: incorrect data");
}
void wake_child(void)
{
if (write(pfd1[1], "p", 1) != 1)
err_exit("write error");
}
void wait_child(void)
{
char c;
if (read(pfd2[0], &c, 1) != 1)
err_exit("read error");
if (c != 'c')
err_exit("WAIT_CHILD: incorrect data");
}
int main (int argc, char *argv[])
{
pid_t pid;
int ret;
initialize();
if ((pid = fork()) < 0) {
err_exit("fork() error\n");
} else if (pid > 0) { //parent
wait_child();
pr_info("parent waken up\n");
pr_info("parent running\n");
pr_info("wake up child\n");
wake_child();
wait(NULL);
} else {
pr_info("child running\n");
pr_info("wake up parent\n");
wake_parent();
wait_parent();
pr_info("child waken up\n");
}
return 0;
}
基于信号SIGUSR1和SIGUSR2实现的同步
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include "include/debug.h"
static volatile sig_atomic_t sigflag; /* set nonzero by sig handler */
static sigset_t mask, omask, zeromask;
static void sig_usr(int signo) /* one signal handler for SIGUSR1 and SIGUSR2 */
{
pr_info("catch signal:%d\n", signo);
sigflag = 1;
}
void initialize(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
err_exit("signal(SIGUSR1) error");
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
err_exit("signal(SIGUSR2) error");
sigemptyset(&zeromask);
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
if (sigprocmask(SIG_BLOCK, &mask, &omask) < 0)
err_exit("SIG_BLOCK error");
}
void wake_parent(pid_t pid)
{
kill(pid, SIGUSR2); /* tell parent we're done */
}
void wait_parent(void)
{
while (sigflag == 0)
sigsuspend(&zeromask); /* and wait for parent */
sigflag = 0;
/* Reset signal mask to original value */
if (sigprocmask(SIG_SETMASK, &omask, NULL) < 0)
err_exit("SIG_SETMASK error");
}
void wake_child(pid_t pid)
{
kill(pid, SIGUSR1); /* tell child we're done */
}
void wait_child(void)
{
while (sigflag == 0)
sigsuspend(&zeromask);
sigflag = 0;
/* Reset signal mask to original value */
if (sigprocmask(SIG_SETMASK, &omask, NULL) < 0)
err_exit("SIG_SETMASK error");
}
int main (int argc, char *argv[])
{
pid_t pid;
int ret;
initialize();
if ((pid = fork()) < 0) {
err_exit("fork() error\n");
} else if (pid > 0) { //parent
wait_child();
pr_info("parent waken up\n");
pr_info("parent running\n");
pr_info("wake up child\n");
wake_child(pid);
wait(NULL);
} else {
pr_info("child running\n");
pr_info("wake up parent\n");
wake_parent(getppid());
wait_parent();
pr_info("child waken up\n");
}
return 0;
}
其他方式
system v IPC、posix IPC这两种当然也可以实现进程同步,但是不在本文讲解。