linux中的信号处理和中断的函数调用?

时间:2015-01-02 12:31:06

标签: c++ c process signals shared-memory

我需要解决一个被描述为

的问题

有两个过程p1,p2和两个变量x,y过程p1和p2应该更新x和y的值,因为p1将更新y = x + 1并且p2将更新x = y + 1且具有一致性.i.e。当p1同时读取x时,p2不能写入x的更新值,并且当p1同时写入y时,p2不能读取y的值。

通过查看问题,我们可以观察到存在死锁。 (read-x by p1)-->(read-y by p1) -->(update-y by p1)-->(read-y by p2)-->(read-x by p2) --> (update-x by p2 )

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

它打印正确(一致)输出,但此实现存在问题 最初打印输出需要几秒钟,然后一次打印大量序列(一串行)。

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

有人可能建议使用相同数量的睡眠时间,但它没有效果。

    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;
}

1 个答案:

答案 0 :(得分:0)

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

您的问题最终是并发访问的问题,解决方案是使用锁。锁允许程序/线程以原子方式完成某些任务。策略是以这样的方式使用两个进程/线程共享的锁LGET(L); do some task; RELEASE(L);

您的代码中出现的问题是信号传递会中断您的sleep来电。当这样的呼叫中断时,它不会在处理结束时重新启动。曼努埃尔说:

  

如果sleep()函数由于传递信号而返回,   返回的值将是未睡眠的数量(请求的时间   减去实际睡觉的时间,以秒为单位。

所以你可以像这样修改你的循环:

   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接口,而是sigaction这样更安全可靠(您永远不必重置信号处理程序中的signal处理,例如)。