使用C ++停止并开始在Linux中再次运行进程

时间:2009-01-07 21:47:23

标签: c++ linux process controls

我有两个进程和一个共享内存区域,我的工作流程是这样的。进程A在共享内存中写入一些数据,之后它应该等待并向其他进程B发送信号以开始运行。进程B应该从共享内存中读取一些数据做一些东西写入结果,然后向进程A发送一个信号继续运行,此进程B应该等待。

任何人都可以提供一个示例或地方,我可以找到如何停止进程以及如何重新开始运行该进程?我在Linux和C ++工作。

我已经有了信号量,但是我不喜欢它,它是一个进程停止从共享内存中一直读取的一堆秒,直到它检测到它可以运行。这就是为什么我只想在恰当的时刻发出信号

使用解决方案进行更新

我选择了stefan.ciobaca的答案作为最爱,因为它是一个完整的解决方案,它有效并且有一个非常好的解释。但在所有其他答案中还有其他有趣的选择。

7 个答案:

答案 0 :(得分:7)

以下是如何完成的概念验证:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <assert.h>

typedef void (*sighandler_t)(int); 

#define SHM_SIZE 8  /* size of shared memory: enough for two 32 bit integers */

volatile int cancontinue = 0;

void halt(char *err) { perror(err); exit(1); }
void handler(int signum) { assert(signum == SIGUSR1); cancontinue = 1; }

int main(void)
{
  key_t key;
  int id;
  int *data;
  pid_t otherpid;

  printf("Hi, I am the %s process and my pid is %d\n", 
#ifdef PRODUCER_MODE
  "writer"
#else
  "reader"
#endif
, getpid());
  printf("Please give me the pid of the other process: ");
  scanf("%d", &otherpid);

  // get a pointer to the shared memory
  if ((key = ftok("test_concur.c", 'R')) == -1) halt("ftok");
  if ((id = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) halt("shmget");
  if ((data = shmat(id, (void *)0, 0)) == (int *)(-1)) halt("shmat");

  sighandler_t oldhandler = signal(SIGUSR1, handler);

  while (1) {
#ifdef PRODUCER_MODE
    printf("Enter two integers: ");
    scanf("%d %d", data, data + 1);

    printf("Sending signal to consumer process\n");
    kill(otherpid, SIGUSR1);

    printf("Waiting for consumer to allow me to continue\n");
    while (!cancontinue);
    cancontinue = 0;

    if (*data + *(data + 1) == 0) { printf("Sum was 0, exiting...\n"); break; }
#else
    printf("Waiting for producer to signal me to do my work\n");
    while (!cancontinue);
    cancontinue = 0;

    printf("Received signal\n");
    printf("Pretending to do a long calculation\n");
    sleep(1);
    int sum = *data + *(data + 1);
    printf("The sum of the ints in the shared memory is %d\n", sum);

    printf("Signaling producer I'm done\n");
    kill(otherpid, SIGUSR1);

    if (sum == 0) break;
#endif
  }

  signal(SIGUSR1, oldhandler);

  /* detach from the segment: */
  if (shmdt(data) == -1) {
    perror("shmdt");
    exit(1);
  }

  // don't forget to remove the shared segment from the command line with

  // #sudo ipcs
  // ... and look for the key of the shared memory segment

  // #ipcrm -m <key>

  return 0;
}

上述程序实际上是两个程序,一个消费者和一个生产者, 取决于你如何编译它。

通过确保PRODUCER_MODE宏来编译生产者 定义如下:

# gcc -Wall -DPRODUCER_MODE -o producer test_concur.c

在不定义PRODUCER_MODE宏的情况下编译使用者:

# gcc -Wall -o consumer test_concur.c

消费者和生产者共享一些全局内存(数据指向8个字节);生产者的角色是从stdin读取两个32位整数并将它们写入共享 记忆。消费者从共享内存中读取整数 计算他们的总和。

将数据写入共享内存后,生产者发信号给 消费者(通过SIGUSR1)它可以开始计算。之后 计算完成后,消费者向生产者发出信号(通过SIGUSR1 再次)它可能继续。

当和为0时,两个进程都会停止。

目前,每个程序都首先输出其pid并从中读取 stdin其他程序的pid。这应该可能:D被替换为 更聪明的东西,取决于你正在做什么。

另外,在实践中,“while(!cancontinue);” - 类似循环应该是 被其他东西取代:D,就像信号量一样。至少你应该这样做 每个循环内都有一个小睡眠。另外,我认为你并不真正需要共享内存来解决这个问题,它应该可以使用消息传递技术。

这是一个示例会话,并行显示:

    # ./producer                                            # ./consumer
    Hi, I am the writer process and my pid is 11357         Hi, I am the reader process and my pid is 11358
    Please give me the pid of the other process: 11358      Please give me the pid of the other process: 11357
    Enter two integers: 2                                   Waiting for producer to signal me to do my work
    3
    Sending signal to consumer process                      Received signal
    Waiting for consumer to allow me to continue            Pretending to do a long calculation
                                        ... some times passes ...
                                                            The sum of the ints in the shared memory is 5
                                                            Signaling producer I'm done
    Enter two integers: 0                                   Waiting for producer to signal me to do my work
    0
    Sending signal to consumer process                      Received signal
    Waiting for consumer to allow me to continue            Pretending to do a long calculation
                                        ... some times passes ...
                                                            The sum of the ints in the shared memory is 0
                                                            Signaling producer I'm done
    Sum was 0, exiting...                                 

我希望这会有所帮助。 (当你运行程序时,确保文件test_concur.c存在(它用于建立共享内存密钥(ftok函数调用)))

答案 1 :(得分:4)

不完全是您所要求的,但是您是否可以使用管道(命名或其他方式)来影响同步?这会给已经知道如何操作的操作系统带来锁定负担。

只是一个想法。


对评论的回应:我的想法是使用管道而不是共享内存来获取更多数据,并免费获得同步。

例如:

  1. 流程A启动,使用popen (3)设置双向管道分叉流程B.
  2. 在叉子之后立即:

    • A做了一些工作并写入管道

    • B尝试读取管道,管道将阻塞,直到进程A写入...

  3. 下一步:

    • 尝试读取管道,管道将阻塞,直到数据可用...

    • B做了一些工作并写入管道

  4. 转到第2步,直到达到结束条件。
  5. 这不是你要求的。没有共享内存,没有信号,但它应该可以做到这一点......

答案 2 :(得分:1)

如何使用Unix domain sockets代替IPC而不是共享内存?这样,每个进程都可以阻止从套接字读取而另一个进程正在工作。

编辑这与dmckee's answer类似,但可以更好地控制阻止和IPC。但是,popen方法肯定更容易实现。

答案 3 :(得分:0)

你真的需要停止进程(退出它),然后重启它,还是只是想让它等到某个事件发生?

如果是后者,您应该阅读IPC和进程同步(例如信号量,互斥量)。

如果是前者,请查看linux中 init 之类的源代码。

答案 4 :(得分:0)

您正在寻找的是阻塞。进程B应该阻塞来自进程A的调用,并且进程A应该阻止进程B的调用。如果一个进程被阻塞(等待来自另一个进程的调用),它就会无所事事地在后台进行,并且只有在收到它时才会被唤醒一个消息。

Select可能是您正在寻找的功能。

答案 5 :(得分:0)

我建议使用信号量来同步进程。

阅读标题,我认为SIGSTOP和SIGCONT可能是可能的,但这可能不是一个好主意;当他们在正确(安全)的地方停下来时,你希望他们停下来。这就是信号量的用途。

许多其他IPC机制也可以实现类似的结果,但信号量是跨进程通信机制(您在单个进程中使用不同线程之间的互斥量)。

答案 6 :(得分:0)

您可能还想查看将在引擎盖下使用共享内存的boost message queues,但隐藏所有难点部分。它提供阻塞和非阻塞功能(听起来你想要阻止)。