【问题标题】:Making sure two processes interleave确保两个进程交错
【发布时间】:2011-05-06 06:21:35
【问题描述】:

在 Linux 上的 C 程序中,我 fork() 后跟 execve() 两次以创建两个运行两个单独程序的进程。如何确保两个子进程的执行交错​​? 谢谢 尝试按照下面给出的答案执行上述任务,但似乎遇到 sched_scheduler() 进程挂起。包括下面的代码...replay1 和 replay2 是两个程序,它们分别简单地打印“Replay1”和“Replay2”。

# include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sched.h>


void main()
{
 int i,pid[5],pidparent,new=0;
 char *newargv1[] = {"./replay1",NULL};
 char *newargv2[] = {"./replay2",NULL};
 char *newenviron[] = {NULL};
 struct sched_param mysched;
 mysched.sched_priority = 1;
 sched_setscheduler(0,SCHED_FIFO, &mysched);  
 pidparent =getpid();

 for(i=0;i<2;i++)
 {
   if(getpid()==pidparent)
   {
    pid[i] = fork();
    if(pid[i] != 0)
    kill(pid[i],SIGSTOP);
    if(i==0 && pid[i]==0)
     execve(newargv1[0], newargv1, newenviron);
    if (i==1 && pid[i]==0)
     execve(newargv2[0], newargv2, newenviron);       
   }
 }
for(i=0;i<10;i++)
 {
   if(new==0)
    new=1;
   else
    new=0;
   kill(pid[new],SIGCONT);
   sleep(100);
   kill(pid[new], SIGSTOP);
 }


}

【问题讨论】:

  • 你真正想要达到什么目的?
  • 让他们互相等待。
  • 这两个进程共享文件,我正在编写自己的并发解析技术,类似于数据库中的事务,我需要测试我的程序。交错应该是随机的
  • 高优先级线程的等待时间是一个困难的值,因为它必须非常非常小。

标签: c fork


【解决方案1】:

由于您需要随机交错,这里有一个可怕的 hack:

  • 分叉后立即向每个应用程序发送SIGSTOP
  • 使用sched_setscheduler 将您的父应用程序设置为具有实时优先级。这将允许您拥有更细粒度的计时器。
  • 向其中一个子进程发送 SIGCONT。
  • 循环:随机等待一小段时间。向当前正在运行的应用程序发送 SIGSTOP,向另一个应用程序发送 SIGCONT。重复。

这将有助于强制执行交错。它也会使事情变得非常缓慢。您可能还想尝试使用sched_setaffinity 将每个进程分配给不同的 CPU(如果您有双核或超线程 CPU)——这将导致它们有效地同时运行,以 I/O 的等待时间为模。 I/O 等待时间(这可能导致它们等待硬盘,此时它们可能会按顺序唤醒,因此不会交错)可以通过确保它们正在操作的任何数据都在 ramdisk 上来避免(在 linux 上,使用 tmpfs)。

如果这对您来说太粗粒度,您可以使用 ptrace 的 PTRACE_SINGLESTEP 操作一次执行一个 CPU 操作,按照您认为合适的方式进行交错。

【讨论】:

  • 非常感谢..按照建议尝试,我将代码作为对我的问题的编辑。 sched_setscheduler() 似乎挂起进程。非常感谢您的帮助。
  • @Lipika,我建议的操作顺序很重要 - 您在 分叉之前设置了 FIFO 调度程序,这意味着子进程将是实时的,除非它休眠了父进程可能永远没有机会再次运行。
  • 再次感谢..但我认为问题是我的进程不是特权进程,因此无法更改优先级。 sched_getscheduler() 返回 0。
  • 很抱歉更改了我的正确答案,但我在这里发现的问题是“等待随机,短时间”。每当我调用 SIGCONT 时,整个进程都会在父进程再次停止之前运行,并安排下一个子进程。是不是因为子进程执行的时间比父进程的睡眠时间短。尝试使用 nanosleep() 非常非常小的时间间隔,但没有成功获得两个交错的进程。很想知道为什么,但在那之前我会选择 sched_yield() 答案
  • @Lipika,啊,我以为你正在处理一个长期运行的过程。我在 ptrace 上加了一点; sched_yield() 不保证交错,因为进程 A 可能在进程 B 完成启动之前完成......
【解决方案2】:

由于这是出于测试目的,您可以在子进程中的每一行代码之后放置sched_yield(); 调用。


另一个可能的想法是有一个父进程ptrace() 子进程,并使用PTRACE_SINGLESTEP 在逐条指令的基础上交错两个进程的执行。

【讨论】:

  • +1 用于开头短语。您可能想详细说明为什么不这样做,除了测试,虽然..
【解决方案3】:

如果您需要同步它们并且它们是您自己的进程,请使用信号量。如果您无权访问源,则无法同步它们。

【讨论】:

    【解决方案4】:

    如果您的目标是进行并发测试,我只知道两种技术:

    • 使用同步测试准确的场景。例如,进程 1 打开连接并执行查询,然后进程 2 进入并执行查询,然后进程 1 再次激活并获取结果,等等。您可以使用其他人提到的同步技术来执行此操作。然而,获得好的测试场景是非常困难的。我过去很少使用这种方法。

    • 您信任的随机性:启动大量执行长时间运行的测试套件的测试进程。我将这种方法用于多线程和多进程测试(我的案例是测试来自多个进程的设备驱动程序访问而没有蓝屏)。通常,您希望使每个流程的测试套件的流程数和迭代次数可配置,以便您可以快速通过或在发布之前进行更长的测试(在 10-12小时对我们来说并不少见)。此类测试的通常运行以小时为单位。您只需启动进程,让它们运行几个小时,并希望它们能赶上所有的时间窗口。交错通常由操作系统处理,因此您在测试过程中无需担心。

    【讨论】:

    • 但是请注意,一些最糟糕的竞争条件,尤其是涉及恰好在两个连续的 cpu 指令之间被中断的竞争条件,更像是一年一次或十年一次事件。测试很好,但它不能替代审计并发逻辑和制定在纸上的场景,您可以在其中手动调用每个潜在的竞争情况。当然,OP 在任何地方都插入收益率的想法可以通过测试发现这种十年一次的竞赛......
    • 我同意。您应该两者都做:分析您的并发逻辑,并进行详尽的测试。如果你在做分析,你可以从分析中创建测试用例,但是关于随机测试还有很多话要说。他们生活的目的是锻炼你没有想到的互动。
    • 哦,我知道另一种技术。使用 valgrind 的螺纹工具。当然,这并不能代替对问题的正确思考。
    【解决方案5】:

    使用 Bash 而不是 C,作业控制要简单得多。试试这个:

    #! /bin/bash
    
    stop ()
    {
        echo "$1 stopping"
        kill -SIGSTOP $2
    }
    
    cont ()
    {
        echo "$1 continuing"
        kill -SIGCONT $2
    }
    
    replay1 ()
    {
        while sleep 1 ; do echo "replay 1  running" ; done
    }
    
    replay2 ()
    {
        while sleep 1 ; do echo "replay  2 running" ; done
    }
    
    replay1 &
    P1=$!
    stop "replay 1" $P1
    
    replay2 &
    P2=$!
    stop "replay  2" $P2
    
    trap "kill $P1;kill $P2" EXIT
    
    while sleep 1 ; do 
        cont "replay 1 " $P1
        cont "replay  2" $P2
        sleep 3
        stop "replay 1 " $P1
        stop "replay  2" $P2
    done
    

    两个进程并行运行:

    $ ./interleave.sh
    replay 1 stopping
    replay  2 stopping
    replay 1  continuing
    replay  2 continuing
    replay  2 running
    replay 1  running
    replay 1  running
    replay  2 running
    replay 1  stopping
    replay  2 stopping
    replay 1  continuing
    replay  2 continuing
    replay 1  running
    replay  2 running
    replay  2 running
    replay 1  running
    replay  2 running
    replay 1  running
    replay 1  stopping
    replay  2 stopping
    replay 1  continuing
    replay  2 continuing
    replay 1  running
    replay  2 running
    replay 1  running
    replay  2 running
    replay 1  running
    replay  2 running
    replay 1  stopping
    replay  2 stopping
    ^C
    

    【讨论】:

    • 非常感谢,但需要一个 C 程序作为一个更大项目的一部分,并且这些过程会产生由我自己的系统调用包装器处理的系统调用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-02
    • 2021-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-13
    相关资源
    最近更新 更多