c++ - Linux中的信号处理和中断函数调用?

标签 c++ c process signals shared-memory

我需要解决一个问题,描述为

有两个进程 p1、p2 和两个变量 x、y 进程 p1 和 p2 应该更新 x 和 y 的值,因为 p1 将更新 y = x + 1,p2 将更新 x = y + 1 并保持一致性。当 p1 同时读取 x 时,p2 无法写入 x 的更新值,而当 p1 同时写入 y 时,p2 无法读取 y 的值。

通过查看问题,我们可以发现存在死锁。 (p1 读取 x)-->(p1 读取 y)-->(p1 更新 y)-->(p2 读取 y)-->(p2 读取 x) -->(由p2更新x)

为了解决死锁,我编写了一个使用信号和共享内存的程序。 在主函数中,信号处理程序使用 SIGUSR1 和 SIGUSR2 信号号进行注册,该信号号由信号处理程序 func1() 和 func2() 处理。生成的信号也同步 x 和 y 的值。每当进程 p1 完成其工作时,它就会为进程 p2 生成一个信号,该信号使用 Kill(pid,signo) 进行传输,反之亦然 它们在无限循环中完成工作并休眠一段时间。

它打印正确(一致)的输出,但此实现存在问题,如下所示 最初需要几秒钟的时间来打印输出,然后一次打印大量序列(一堆行)。

应该对此代码进行哪些修改,以便它在几乎恒定的时间后打印输出?

有人可能建议使用等量的 sleep 时间,但这没有用。

    void func1(int signo){
        *shm2 = *shm1 +1;
        cout<<"Value of Y is\t"<<*shm2<<"\n";
        signal(signo,func1);
    }

    void func2(int signo){
        *shm1  = *shm2 + 1;
        cout<<"Value of X is\t"<<*shm1<<"\n";
        signal(signo,func2);
    }

    int main(){

    int pid=0,ppid=0;
    int shmid1,shmid2;
    signal(SIGUSR1,func1);
    signal(SIGUSR2,func2);

    shmid1 = shmget(IPC_PRIVATE , sizeof(int) , 0666|IPC_CREAT);
    shmid2 = shmget(IPC_PRIVATE , sizeof(int) , 0666|IPC_CREAT);

    if(shmid1 < 0 || shmid2 < 0 ){
        cout<<"Something goes wrong during creation\n";
        exit(1);
    }
    // Attach shared memory to an address 
    shm1  = (int *) shmat(shmid1 , (void*)0 , 0);
    shm2  = (int *) shmat(shmid2 , (void*)0 , 0);
    if( *shm1 == -1 || *shm2 == -1){
        cout<<"Memory can't be attached\n";
        exit(1);
    }

    pid   = fork();
    if(pid < 0 ){
        cout<<"fork() error\n";
        exit(1);
    }
    ppid  =getppid();
    if(pid > 0){
        while(1){
        sleep(500);
        kill(pid,SIGUSR1);
        }
    }
    else{
        while(1){
        sleep(5);
        kill(ppid,SIGUSR2);
        }
    }
    return 0;
}

最佳答案

这不是死锁。死锁是指 P1 等待 P2 完成而 P2 等待 P1 完成的情况...

您的问题最终是并发访问的问题,解决方案是使用锁。锁允许程序/线程自动完成某些任务。该策略是使用由两个进程/线程共享的锁L,方式如下:GET(L);做一些任务;释放(L);

您的代码中的错误是信号传递中断了您的 sleep 调用。当这样的调用被中断时,它不会在处理结束时重新启动。手册说:

If the sleep() function returns due to the delivery of a signal, the value returned will be the unslept amount (the requested time minus the time actually slept) in seconds.

因此您可以像这样修改循环:

   if (pid > 0) {
        while(1) {
          int v = 500;
          while ((v=sleep(v))!=0); // restart while delay not passed
          kill(pid,SIGUSR1);
        }
    }
    else {
        while(1) {
          int v=5;
          while ((v=sleep(v))!=0); // restart while delay not passed
          kill(ppid,SIGUSR2);
        }
    }

我还建议不要使用旧的 signal 接口(interface),而是使用更安全可靠的 sigaction (您永远不必重置 signal code> 例如在信号处理程序中处理)。

关于c++ - Linux中的信号处理和中断函数调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27742264/

相关文章:

c++ - STL 元编程 - 在编译时创建了哪些类型的模板类?

CS50 PSET 2 凯撒错误结果

c - 如何根据字节数组生成随机数?

c - 如何从 Void 函数返回值?

c - 如何在全局变量中保存进程 ID?

ruby - 使用 Ruby 向子进程发送消息

c++ - 如何使用 visual Studio 2010 编译和构建 librsync?

c++ - 是否存在仍然可达的内存泄漏问题?

c++ - 在 ARM mbed 中使用回调时 undefined reference

azure - 超时超过 3 小时 Automation Runbook Azure