【问题标题】:Is it possible to fork/exec and guarantee one starts before the other?是否可以分叉/执行并保证一个在另一个之前启动?
【发布时间】:2011-08-31 19:55:01
【问题描述】:

正如标题所说。我有一个如下所示的 sn-p 代码:

pid_t = p;

p = fork();

if (p == 0) {
    childfn();
} else if (p > 0) {
    parentfn();
} else {
    // error
}

我想确保父母或孩子在另一个之前执行(但不返回)各自的功能。

调用 sleep() 之类的方法可能会起作用,但不能由任何标准保证,并且只会利用操作系统调度程序的实现细节……这可能吗? vfork 会起作用吗?

edit:这两个函数都找到了 system() 调用的方法,其中一个在另一个启动之前不会返回。所以重申一下:我需要确保父母或孩子只在另一个之前调用他们各自的函数(但不返回,因为它们不会,这是下面所有基于互斥锁的解决方案所提供的)。有任何想法吗?抱歉,不清楚。

edit2:让一个进程调用 sched_yield 和 sleep,我似乎得到了相当可靠的结果。 vfork 确实提供了我正在寻找的语义,但是对我可以在子进程中执行的操作有太多限制(我几乎只能调用 exec)。因此,我找到了一些足够好的解决方法,但没有真正的解决方案。 vfork 可能是最接近我正在寻找的东西,但下面介绍的所有解决方案或多或少都会起作用。

【问题讨论】:

  • 我读到这篇文章是因为您需要一个 可预测的 顺序来调用 childfn() 和 parentfn(),而对其中一个没有特别的偏好 - 对吗?跨度>

标签: c exec fork parallel-processing


【解决方案1】:

这个问题通常可以通过mutexsemaphore 来解决。例如:

// Get a page of shared memory
int pagesize = getpagesize();
void *mem = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if(!mem)
{
  perror("mmap");
  return 1;
}

// Put the semaphore at the start of the shared page.  The rest of the page
// is unused.
sem_t *sem = mem;
sem_init(sem, 1, 1);

pid_t p = fork();

if (p == 0) {
    sem_wait(sem);
    childfn();
    sem_post(sem);
} else if (p > 0) {
    sem_wait(sem);
    parentfn();
    sem_post(sem);

    int status;
    wait(&status);
    sem_destroy(sem);
} else {
    // error
}

// Clean up
munmap(mem, pagesize);

您也可以在共享内存区域中使用互斥体,但您需要确保使用非默认属性创建进程共享属性,该属性称为共享(通过pthread_mutexattr_setpshared(&mutex, PTHREAD_PROCESS_SHARED))才能正常工作。

这确保了childfnparentfn 中只有一个会在任何给定时间执行,但它们可以按任意顺序运行。如果您需要先运行特定的信号量,请以 1 而不是 0 的计数开始信号量,并让需要首先运行的函数不等待信号量(但在完成后仍会发布)。您也许还可以使用具有不同语义的condition variable

【讨论】:

  • 如果不将互斥锁放在fork 之前的共享内存段中,我认为这是行不通的。否则互斥锁会在两个进程中被复制。
  • Linux 互斥体在进程之间工作得非常好,只要它们是使用进程共享属性创建的。
  • @R.:另一个好点,我忘记了互斥体属性。我使用默认属性进行的第一次测试没有成功,因为互斥锁默认是进程私有的。
  • 过去即使没有进程共享属性也可以工作(使用旧 glibc 或旧内核),但 Linux 添加了私有 futex 标志以优化常见的非进程-通过将虚拟地址直接用作 futex 哈希而不是将其解析为底层映射来共享大小写。
【解决方案2】:

互斥锁应该可以解决这个问题。在调用 fork 之前锁定互斥锁,并让第一个函数正常执行,而第二个函数尝试声明互斥锁。第一个应该在互斥锁完成后解锁,第二个会等到它空闲。

编辑:互斥锁必须位于两个进程的共享内存段中

【讨论】:

  • 这仅在创建具有进程共享属性的互斥锁时有效。对于不熟悉线程同步原语的程序员来说,有更简单的解决方案...
【解决方案3】:

最安全的方法是使用(命名的)管道或套接字。一侧写入,另一侧读取。读者无法阅读尚未写入的内容。

【讨论】:

  • +1 这是多进程程序最简单、最经典的解决方案,比将共享内存和 pthread 同步原语引入图片要简单得多。
  • 作者甚至不用写,直接关闭就可以了(前提是读者也关闭了)。
  • 解决同步问题。
【解决方案4】:

使用信号量确保一个在另一个之前启动。

【讨论】:

    【解决方案5】:

    您可以使用原子变量。在你 fork/thread/exec 之前将它设置为零,让第一个进程在它进入函数之前(或者更好,之后)将它设置为一个,然后让第二个等待 while(flag == 0)。

    【讨论】:

    • 这会让你的 CPU 不必要地旋转,浪费电力。使用条件变量或信号量会更好,您可以等待而无需忙于等待。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    • 2020-09-12
    相关资源
    最近更新 更多