我有两个进程和一个共享内存区域,我的工作流程是这样的。进程A在共享内存中写入一些数据,之后它应该等待并向其他进程B发送信号以开始运行。进程B应该从共享内存中读取一些数据做一些东西写入结果,然后向进程A发送一个信号继续运行,此进程B应该等待。
任何人都可以提供一个示例或地方,我可以找到如何停止进程以及如何重新开始运行该进程?我在Linux和C ++工作。
我已经有了信号量,但是我不喜欢它,它是一个进程停止从共享内存中一直读取的一堆秒,直到它检测到它可以运行。这就是为什么我只想在恰当的时刻发出信号
使用解决方案进行更新
我选择了stefan.ciobaca的答案作为最爱,因为它是一个完整的解决方案,它有效并且有一个非常好的解释。但在所有其他答案中还有其他有趣的选择。
答案 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)
不完全是您所要求的,但是您是否可以使用管道(命名或其他方式)来影响同步?这会给已经知道如何操作的操作系统带来锁定负担。
只是一个想法。
对评论的回应:我的想法是使用管道而不是共享内存来获取更多数据,并免费获得同步。
例如:
popen (3)
设置双向管道和分叉流程B. 在叉子之后立即:
A做了一些工作并写入管道
B尝试读取管道,管道将阻塞,直到进程A写入...
下一步:
尝试读取管道,管道将阻塞,直到数据可用...
B做了一些工作并写入管道
这不是你要求的。没有共享内存,没有信号,但它应该可以做到这一点......
答案 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,但隐藏所有难点部分。它提供阻塞和非阻塞功能(听起来你想要阻止)。