c - semop( ) 失败,错误号 4。semop() 是否支持进程内的线程竞争?

标签 c linux semaphore

我在一个进程中有两个线程。这两个线程竞争共享内存,试图通过信号量进行同步。但是,当一个线程紧挨着另一个线程调用 semop 函数时,我随机遇到了 errno 4 失败。我做了一点挖掘,发现调用似乎被系统调用中断了。

EINTR 在此系统调用中被阻塞时,进程捕获了一个信号;见信号(7)。 errno 4 是这个吗?

请注意第 583 和 601 行。

哪个系统调用中断了呢?函数 semop() 本身?有什么方法可以忽略此系统调用中断或恢复/重新启动此功能?

semop可以在多线程环境下使用吗?

[Switching to Thread -1208269120 (LWP 4501)]
GetMyQue2Wait (MyModule=RM, wait_shm_ptr=0xbf8a5cf4) at tdm_ipc.c:247
247                                             TDM_SEM_P( MyModule );
(gdb) s
tdm_sem_p (mid=RM) at tdm_ipc.c:579
579             sem_b.sem_num = 0;
(gdb) s
580             sem_b.sem_op = -1;
(gdb) s
581             sem_b.sem_flg = SEM_UNDO;
(gdb) s
583             if (semop(TDM_M[mid].semid, &sem_b, 1) == -1)
(gdb) s
[Switching to Thread -1208480880 (LWP 4506)]

GetMyQue2Send (MyModule=RM, send_shm_ptr=0xb7f7ff54) at tdm_ipc.c:180
180             DMINT           TryTimes = SEND_TIMES;
(gdb) s
353             TDM_SEM_V( DstModule );
(gdb) s
tdm_sem_v (mid=RM) at tdm_ipc.c:597
597             sem_b.sem_num = 0;
(gdb) s
598             sem_b.sem_op = 1;
(gdb) s
599             sem_b.sem_flg = SEM_UNDO;
(gdb) s
601             if (semop(TDM_M[mid].semid, &sem_b, 1) == -1)
(gdb) s
606             return SUCC;
(gdb) s
607     }


(gdb) s
RM:4501: V operation on Semaphore .
SEND_MSG (SrcModule=51, DstModule=RM, msg_ptr=0xb7f7ff94, MsgLength=28) at tdm_ipc.c:368
368             printf("%s:%d: SEND_MSG: succeeded.\n",
(gdb) s
RM:4501: SEND_MSG: succeeded.
[Switching to Thread -1208269120 (LWP 4501)]
tdm_sem_p (mid=RM) at tdm_ipc.c:585
585                     printf("thread %u: errno = %d\n", (unsigned int)pthread_self(),errno);
(gdb) s
thread 3086698176: errno = 4
[Switching to Thread -1208480880 (LWP 4506)]



 main thread:

        ...
         while(1)
           {
                 if ((RetVal = WAIT_MSG( p1, &Msg )) !=SUCC)
                 {
                     switch ( RetVal )
                     {
                     ...
                      }
                  }
            }
     ------------------------------------  
        thread1:
        ...
        send(src, dst, &msg, lenght);

        /* both SEND_MSG() and WAIT_MSG() have an operation P and V on semid by calling the following */

        DMINT tdm_sem_p( key_t semid )
        {
           struct sembuf sem_b;

           sem_b.sem_num = 0;
           sem_b.sem_op = -1;
           sem_b.sem_flg = SEM_UNDO;

           if (semop(semid, &sem_b, 1) == -1)
           {
              printf("thread %u: errno = %d\n", (unsigned int)pthread_self(),errno);

              return S_PFAIL;
           }

           return SUCC;
        }

        DMINT tdm_sem_v( key_t semid )
        {
           struct sembuf sem_b;

           sem_b.sem_num = 0;
           sem_b.sem_op = 1;
           sem_b.sem_flg = SEM_UNDO;

           if (semop(semid, &sem_b, 1) == -1)
           {
              return S_VFAIL;
           }

           return SUCC;
        }

        /* semid is init by the following */
        DMINT tdm_set_sem(key_t semid)
        {
           union semun sem_union;
           sem_union.val = 1;

           if (semctl(semid, 0, SETVAL, sem_union) == -1)
           {
              return FAILURE;
           }
           return SUCC;
        }

这个问题有另一个链接,可能有一个错误的问题描述。 P semaphore failed

谢谢。

最佳答案

Errno 4 确实是 EINTR。当您收到该错误时,这意味着您正在运行的系统调用(在本例中为 semop)被信号中断。

在这种情况下,您有责任重新启动系统调用。只有一组有限的系统调用会自动重启,并且只有在使用 SA_RESTART 标志设置信号处理程序时才会自动重启。参见 signal(7)有关详细信息,请参阅“信号处理程序中断系统调用和库函数”部分。您会注意到 semop从不重新启动的系统调用列表中,无论信号处理程序的配置如何。

如何重新开始通话由您决定。其中一种方法是执行以下操作:

int rc;

while ((rc = semop(...)) == -1) {
  if (errno != EINTR) {
    break;
  } else {
    // decide whether to restart the call after interruption
    // or not
  }
}
// here, if rc == 0, semop worked, otherwise an error different from
// EINTR happened (or you decided not to restart)

除非您有该信号的处理程序,否则您不知道是什么信号中断了给定的系统调用。 gdb 确实有 options for signal handling不过,所以您可以尝试找出答案。尝试从 handle all print 开始。

关于c - semop( ) 失败,错误号 4。semop() 是否支持进程内的线程竞争?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9579158/

相关文章:

c# - tcp 服务器在第一次循环后失败

linux - 如何从具有多天数据的日志文件中检索一天数据

c - pthread_join() 和卡住执行

c - 为什么这个信号量卡住了

由于 `dm_task_set_cookie failed`,Docker 无法启动

c - 将 Solaris/Linux 上的 ANSI 代码移植到 Windows Server 2012

c - 声明但未定义的函数的返回类型和参数中的不完整类型

python - Python如何在远程机器上执行命令并等待执行完成?

linux - 如何将 Inkscape 默认导出颜色从黄色更改为白色?

c - 使用 AF_UNSPEC 时,getaddrinfo() 仅返回 ipv6