Атомика и `errno`: разумно ли использовать атомы C ++ 11 для чтения защищенного значения errno? - PullRequest
0 голосов
/ 04 декабря 2018

Обработка errno - это одна из проблем использования POSIX API в многопоточной среде.Было бы разумно использовать блокировку с использованием std::atomic, как показано ниже?

class FastLock{
    std::atomic_int value;
public:
    FastLock()
    : value{0}{}

    void unlock()
    {
        value.store(0,std::memory_order_release);
    }

    bool try_lock()
    {
        int r = value.exchange(1,std::memory_order_acquire);
        return !r;
    }
};

Контекст будет похож на это:

template<typename function, typename ...args>
auto shield(function _fn){
    static FastLock* lk = new FastLock{};
    return [=](args... _v){
        while(lk->try_lock());
        auto ret = std::forward(_fn, _v...);
        auto errval = errno;
        lk->unlock();
        return std::make_pair(ret,errval);
    };
}

Это приведет к любому видулибо неопределенное поведение, либо поведение, определяемое реализацией?

1 Ответ

0 голосов
/ 04 декабря 2018

В то время как старый стандарт POSIX 1988 года требовал, чтобы errno был глобальным объектом, это больше не относится к последующим версиям.По крайней мере POSIX.1-2001 требует, чтобы errno был локальным для потока.Я подозреваю, что это уже требовалось POSIX.1c-1995, который определяет потоки POSIX, но у меня нет доступа к этому документу, поэтому я не могу проверить.

Я бы не ожидал, что система POSIX, которая поддерживаетC ++ 11 также не будет поддерживать POSIX 2001, и поэтому использование атомных элементов C ++ 11 вряд ли будет необходимо.

Тем не менее, в то время как стандарт C не требует, чтобы errno былглобальный объект (по крайней мере, C99 этого не делает), он также не гарантирует локальность потока errno.Таким образом, блокировка errno может быть необходима в не POSIX-системах или старых POSIX-системах, которые не обеспечивают локальность потоков.И если по какой-то причине платформа поддерживает C ++ 11, то атомарность C ++ 11 может быть идеальным выбором для реализации блокировки - или не может быть.По крайней мере, теоретически.

Обратите внимание, что для обеспечения безопасности потоков вам необходимо убедиться, что все вызовы функций, которые могут устанавливать errno, должны использовать блокировку.Если вы используете какие-либо библиотеки, которые могут использовать такие стандартные функции, вы также должны блокировать вызовы для таких функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...