103-atfork 与 fork

linux 提供了一个称之为 pthread_atfork 的函数,它允许我们事先注册三个回调函数。一旦 fork 被调用,这三个回调函数会被执行。

1. 函数原型

int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));

上面三个回调函数,分别为 prepare 函数,parent 函数,child 函数。这些函数的调用时机如下:

  • prepare 函数是在 fork 还会产生子进程时调用
  • parent 和 child 是在产生子进程后调用
  • parent 在父进程中调用,child 在子进程中调用

用伪代码来说明调用时机:

prepare();
pid = fork();

if (pid > 0) {
  parent();
}
else if (pid == 0) {
  child();
}

只不过 atfork 注册的这几个函数调用时间是在进入 fork 后,返回 fork 前而已。但是它们做的事情,几乎等同于上面的伪代码。

2. 利用 atfork 解决 fork 死锁

程序 atfork_lock 是解决上一篇文章中的 fork 死锁问题,你会发现,它的解决方案其实和上一文中的几乎差不多。只是,更推荐用 atfork 这种方式。

2.1 代码

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>

#define PERR(err, msg) do { errno = err; perror(msg); exit(-1); } while(0)

int total = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void prepare() {
  int err;
  puts("preparing locks...");
  err = pthread_mutex_lock(&lock);
  if (err != 0) PERR(err, "prepare lock failed");
}

void parent() {
  int err;
  puts("parent unlocking locks...");
  err = pthread_mutex_unlock(&lock);
  if (err != 0) PERR(err, "parent unlock failed");
}

void child() {
  int err;
  puts("child unlocking locks...");
  err = pthread_mutex_unlock(&lock);
  if (err != 0) PERR(err, "child unlock failed");
}


void* fun(void* arg) {
  while(1) {
    pthread_mutex_lock(&lock);
    total++;
    puts("fun:  total++");
    sleep(5);
    pthread_mutex_unlock(&lock);
    sleep(1);
  }
  return NULL;
}

int main() {
  int err;
  pid_t pid;
  pthread_t tid;
  pthread_create(&tid, NULL, fun, NULL);
  err = pthread_atfork(prepare, parent, child);
  if (err != 0) PERR(err, "atfork");

  sleep(1);
  puts("parent about to fork ...");
  pid = fork();
  if (pid < 0) PERR(errno, "fork");
  else if (pid == 0) {
    // child
    int status;
    while(1) {
      pthread_mutex_lock(&lock);
      total++;
      puts("child: total++");
      sleep(2);
      pthread_mutex_unlock(&lock);
      sleep(1);
    }
    exit(0);
  }

  pthread_join(tid, NULL);
}

2.2 编译和运行

  • 编译运行
$ gcc atfork_lock.c -o atfork_lock -lpthread
$ ./atfork
  • 运行结果


这里写图片描述

3. 总结

  • 知道 atfork 注册的三个回调函数调用时机
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值