C: Обработка сигналов и семафоры
Я пытаюсь лучше понять семафоры и весь этот джаз, и для этого я программирую сервер и клиентов, которые общаются, используя общую память и семафоры. Это работает довольно хорошо и все, но я не уверен, что понимаю, как правильно работает обработка сигналов в этом случае. Это пример кода с моего сервера. Я понимаю, что может быть несколько лишним проверить оба, но я бы хотел понять странное поведение, которое я испытываю:
sig_atomic_t running = 1;
while(running == 1) {
if (sem_wait(server) == -1) {
//exit and print error A
}
if(running == 0) {
//exit and print error B
}
/* do server stuff */
if (sem_post(client) == -1) {
//exit and print error
}
}
server - это имя семафора сервера, client - это имя семафора клиента (что в данном случае не имеет значения). running (которая на самом деле является глобальной) - это переменная, которую я использую в своем обработчике сигналов:
static void init_signalhandler() {
struct sigaction sa;
sa.sa_handler = terminate;
if(sigemptyset(&(sa.sa_mask)) == -1) {
bail_out(EXIT_FAILURE, "sigemptyset error");
}
if(sigaction(SIGINT, &sa, NULL) == -1) {
bail_out(EXIT_FAILURE, "sigaction1 error");
}
if(sigaction(SIGTERM, &sa, NULL) == -1) {
bail_out(EXIT_FAILURE, "sigaction2 error");
}
}
static void terminate(int e) {
running = 0;
sem_post(server);
}
Где bail_out - пользовательская функция печати / выхода из ошибки.
В основном, независимо от того, что я делаю, каждый раз, когда я запускаю сервер, он sem_wait(server)
часть. Если я пытаюсь убить его, отправляя SIGINT, иногда он печатает ошибку A, а иногда - ошибку B. Это выглядит совершенно случайно. Это как бы вынуждает меня использовать бегущую переменную, хотя иногда семафор пропускается, а в других - нет.
1 ответ
Как вы не справляетесь с EINTR
от sem_wait(3)
поведение точно так, как и должно быть.
Например, ты ждешь в sem_wait(server)
, Вы получаете SIGINT
и обращаться с этим правильно. Ваша функция sem_wait вернется -1
и ты спасешься. Что вы должны сделать вместо этого:
if (sem_wait(s_server) == -1) {
if(errno == EINTR) continue;
bail_out(EXIT_FAILURE, "sem_wait(3) failed");
}
Это отлавливает ошибки из-за сигналов в подпрограмме sem_wait, и вы можете корректно завершить работу вашего сервера, когда переходите к началу цикла, видите, что для выполнения задано значение 0, и пропустите цикл.
Смотрите страницу руководства sem_wait(3), "Возвращаемые значения" для более подробной информации о том, какие ошибки могут быть обработаны.