Как обработать EINTR (прерванный системный вызов)

[C++]

это используется в операторе присваивания, где большую часть времени необходимо проверить и предотвратить странный (неумышленный, опасный, или просто пустая трата времени для программы) вещи как:

A a;
a = a;

Ваш оператор присваивания будет записан:

A& A::operator=(const A& a) {
    if (this == &a) return *this;

    // we know both sides of the = operator are different, do something...

    return *this;
}
5
задан Maus 4 November 2009 в 14:40
поделиться

2 ответа

Код, вызывающий запись (или другие операции блокировки), должен знать EINTR. Если сигнал возникает во время операции блокировки, то операция либо (а) вернет частичное завершение, либо (б) вернет ошибку, ничего не сделает и установит для errno значение EINTR.

Итак, для записи типа «все или сбой» операцию, которая повторяет попытку после прерывания, вы бы сделали что-то вроде этого:

while(size > 0) {
    int written = write(filedes, buf, size);
    if (written == -1) {
        if (errno == EINTR) continue;
        return -1;
    }
    buf += written;
    size -= written;
}
return 0; // success

Или для чего-то немного лучшего, которое повторяет EINTR, записывает столько, сколько может, и сообщает, сколько записано при неудаче (чтобы вызывающий мог решить следует ли и как продолжать частичную запись, которая завершается неудачно по причине, отличной от прерывания по сигналу):

int total = 0;
while(size > 0) {
    int written = write(filedes, buf, size);
    if (written == -1) {
        if (errno == EINTR) continue;
        return (total == 0) ? -1 : total;
    }
    buf += written;
    total += written;
    size -= written;
}
return total; // bytes written

GNU имеет нестандартный макрос TEMP_FAILURE_RETRY, который может представлять интерес, хотя я никогда не могу найти для него документацию, когда я захочу. В том числе сейчас.

17
ответ дан 18 December 2019 в 08:29
поделиться

См. Также обсуждение "режима проигравшего" в Чем хуже, тем лучше

2
ответ дан 18 December 2019 в 08:29
поделиться