我正在尝试通过在C中使用POSIX信号来实现进程间通信,尤其是我正在编写Ping-Pong问题。所以这是我的源代码:
#define CHILD 0
#define PARENT 1
int flag[2];
void handler(int sig) {
if (sig == SIGUSR1) {
flag[PARENT] = 1;
} else {
flag[CHILD] = 1;
}
return;
}
void child_process() {
while (1) {
printf("Ping!\n");
kill(getppid(), SIGUSR2);
while (flag[PARENT] == 0) { }
}
return;
}
void parent_process(pid_t t) {
while (1) {
//kill(t, SIGUSR1);
while (flag[CHILD] == 0) { }
printf("Pong!\n");
kill(t, SIGUSR1);
}
return;
}
void setup() {
flag[CHILD] = 0;
flag[PARENT] = 0;
signal(SIGUSR1, handler);
signal(SIGUSR2, handler);
}
int main(int argc, char* argv[]) {
setup();
pid_t t = fork();
if (t == 0) {
child_process();
} else {
parent_process(t);
}
return 0;
}
我的程序运行不正常,因为有时我得到“Pong!” “傍”! “傍”!或者“Ping!” “平安!”输出。有什么问题?
还有一个问题,我处理信号的方式是否正确?或者有更先进的方法来做到这一点?
答案 0 :(得分:2)
(1)父母和孩子不共享相同的内存。 flag [CHILD]和flag [PARENT]永远不会相互了解,因为它们在不同的进程中是不同的副本。
(2)是的,几乎关于你的信号处理的一切都是错误的,你正在尝试做什么。您正在尝试同步信号,因此您需要使用实际同步它们的机制,例如sigsuspend
。
#define _POSIX_C_SOURCE 1
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
void sig_hand(int sig) {}
sigset_t saveMask, blockMask;
void child_process()
{
int x = 0;
while(x < 10)
{
if (sigsuspend(&saveMask) == -1 && errno != EINTR)
errExit("sigsuspend");
printf("Pong %d!\n", ++x);
kill(getppid(), SIGUSR1);
}
return ;
}
void parent_process(pid_t pid)
{
int y = 0;
while (y < 10)
{
printf("Ping %d!\n", ++y);
kill(pid, SIGUSR1);
if (sigsuspend(&saveMask) == -1 && errno != EINTR)
errExit("sigsuspend");
}
return ;
}
int main(int argc, char* argv[])
{
//block SIGUSR1 in parent & child until ready to process it
sigemptyset(&blockMask);
sigaddset(&blockMask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &blockMask, &saveMask) == -1)
errExit("sigprocmask");
//set up signal handler for parent & child
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sig_hand;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
errExit("sigaction");
pid_t pid = fork();
if (pid == 0)
child_process();
else
parent_process(pid);
return 0;
}
答案 1 :(得分:0)
虽然这可能不是你的问题,但是记住,当你修改与程序流异步的变量时,你需要使这些变量变得不稳定,这样编译器就不会优化对它们的访问。
我认为semaphore.h有更多有用的工具(sem_open,sem_post,sem_wait,sem_trywait)。
答案 2 :(得分:0)
我使用sigaction()
和pause()
函数以及nanosleep()
来限制活动。
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
enum { MAX_PINGS = 10 };
static sig_atomic_t sig_num;
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, ": (%d) %s", errnum, strerror(errnum));
putc('\n', stderr);
}
static void catcher(int sig)
{
sig_num = sig;
}
static void child_process(void)
{
struct timespec nap = { .tv_sec = 0, .tv_nsec = 100000000 };
while (1)
{
pause();
printf("Pong!\n");
nanosleep(&nap, 0);
kill(getppid(), SIGUSR1);
}
}
static void parent_process(pid_t pid)
{
struct timespec nap = { .tv_sec = 0, .tv_nsec = 100000000 };
for (int pings = 0; pings < MAX_PINGS; pings++)
{
printf("Ping %d!\n", pings);
nanosleep(&nap, 0);
kill(pid, SIGUSR1);
pause();
}
kill(pid, SIGTERM);
}
int main(void)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = catcher;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
err_exit("Failed to set SIGUSR1 handler");
pid_t pid = fork();
if (pid < 0)
err_exit("Failed to fork()");
else if (pid == 0)
child_process();
else
parent_process(pid);
return 0;
}
变量sig_num
用于平息编译器关于未使用的参数(到catcher
函数)的投诉。信号捕捉器设置在fork()
之前。子进程暂停,直到信号到达;然后打印&#39; Pong!&#39;,小睡1/10秒,然后通知父进程唤醒。父进程打印&#39; Ping!&#39;,小睡,发信号通知子进程,并暂停直到信号到达。它将循环限制为10(足以显示它正在工作),并在完成后,在退出之前终止子循环。
$ ./pingpong
Ping 0!
Pong!
Ping 1!
Pong!
Ping 2!
Pong!
Ping 3!
Pong!
Ping 4!
Pong!
Ping 5!
Pong!
Ping 6!
Pong!
Ping 7!
Pong!
Ping 8!
Pong!
Ping 9!
Pong!
$
显然,在乒乓球上打印一个计数器并不困难。也是值。