semop () завершился неудачно с ошибкой 4. Доза semop () поддерживает гонку потоков внутри процесса? - PullRequest
1 голос
/ 06 марта 2012

У меня есть две темы в процессе. Эти два потока участвуют в общей памяти, которая пытается синхронизироваться семафором. Но я случайно получил ошибку с ошибкой 4, когда один поток находится рядом с другим, чтобы вызвать функцию semop. Я немного покопался и обнаружил, что кажется, что вызов был прерван системным вызовом.

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

Спасибо.

Ответы [ 2 ]

6 голосов
/ 06 марта 2012

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 есть опции для обработки сигналов , так что вы можете попытаться выяснить это. Попробуйте handle all print, чтобы начать с возможно.

0 голосов
/ 26 февраля 2013

ограничить процесс, о котором идет речь ... при сбое в работе семопа вы должны увидеть сигнал, прерывающий его.

...