многоразовый барьер простая (переменная) реализация

std::mutex mutex;
std::condition_variable cv;
uint8_t size = 2;
uint8_t count = size;
uint8_t direction = -1;

const auto sync = [&size, &count, &mutex, &cv, &direction]()  //.
{
    {
        std::unique_lock<std::mutex> lock(mutex);
        auto current_direction = direction;
        if (--count == 0)
        {
            count = size;
            direction *= -1;
            cv.notify_all();
        }
        else
        {
            cv.wait(lock,
                    [&direction, &current_direction]()  //.
                    { return direction != current_direction; });
        }
    }
};

как указано в первом непринятом ответе многоразового барьера

«поколение» должно храниться внутри объекта-барьера, чтобы следующее поколение не могло манипулировать «условием» пробуждения текущего поколения для данного набора потоков. Что мне не нравится в первом непринятом ответе, так это растущий счетчик поколений, я считаю, что нам нужно только различать максимум два поколения, то есть если поток удовлетворил условию ожидания и начал другой вызов барьерной синхронизации в качестве второго непринятого решения предполагает, что второе решение, однако, было несколько сложным, и я считаю, что приведенного выше фрагмента было бы даже достаточно (в настоящее время реализовано локально внутри основного, но может быть абстрагировано в структуру). Прав ли я в своем «убеждении», что барьер можно использовать одновременно не более чем для двух поколений?


person mkmostafa    schedule 26.09.2017    source источник
comment
Плохие вещи действительно произойдут, если count равно 0 в точке захвата.   -  person Bathsheba    schedule 26.09.2017
comment
можно подробнее? count в настоящее время отображается только потому, что я использую лямбда, я бы изменил все это на структуру, которая принимает размер в качестве входных данных с функцией-членом без каких-либо параметров.   -  person mkmostafa    schedule 26.09.2017
comment
Я не уверен, что понимаю цель здесь. Сверху возможно следующее. Поток 1 ожидает смены направления. Поток 2 меняет направление и уведомляет всех. Но прежде чем поток 1 сможет проснуться и проверить условие, другие потоки вызывают sync достаточное количество раз, чтобы снова изменить направление. Затем поток 1 обнаружил бы, что условие ложно, предположил бы ложное пробуждение и снова заснул бы. В конечном итоге он проснется, когда направление снова изменится, в третий (или, возможно, пятый, или Nth для сколь угодно большого нечетного N) времени.   -  person Igor Tandetnik    schedule 30.09.2017
comment
Но sync нельзя вызвать достаточно, чтобы вызвать другой щелчок без участия потока 1. Все участвующие потоки должны вызывать синхронизацию. Последний поток всегда переворачивается, поэтому в вашем примере все потоки вызывают синхронизацию, кроме m потока 1 (отложенного), который в конечном итоге вызовет синхронизацию после того, как он проснется и сделает переворот   -  person mkmostafa    schedule 03.10.2017