станд.:: список, распараллеливающий push_back, передняя сторона, pop_front

Одна вещь знать состоит в том, что эта техника не обнулит дополнительные байты. Например:

struct foo
{
    char c;
    int  i;
};

foo a = {0};

Не то же как:

foo a;
memset(&a,0,sizeof(a));

В первом случае, дополните байты между c, и я являюсь неинициализированным. Почему Вы заботились бы? Ну, если Вы сохраняете эти данные на диск или отправляете их по сети или что бы то ни было, у Вас могла бы быть проблема безопасности.

6
задан Steven smethurst 3 December 2009 в 22:46
поделиться

5 ответов

Является ли std :: list потокобезопасным?

Текущий стандарт C ++ даже не признает существование потоков, поэтому std :: list определенно нет. Однако разные реализации могут обеспечивать (разные уровни) потокобезопасность.

Что касается вашего кода: если вам нужен замок, используйте его. Эта переменная bool может не помочь, когда потоки выполняются на разных ядрах, которые извлекают их из разных кешей. Вместо этого используйте настоящий мьютекс.

15
ответ дан 8 December 2019 в 05:21
поделиться

Нет, потокобезопасность не гарантируется.

Ваш механизм синхронизации неисправен. Вы разрешаете thread1 изменять список, пока thread2 работает с ним. Это может вызвать проблемы. Кроме того, вам следует сделать переменную блокировки изменчивой .

6
ответ дан 8 December 2019 в 05:21
поделиться

Вы правы, предполагая, что потокобезопасность stl-списка не гарантируется.

Также ваш механизм синхронизации, вероятно, не очень хорош.

Внутри thread2 вы этого не делаете. t lock ваш bool, поэтому у вас есть проблема.

Вероятно, вы должны как минимум поставить квалификатор volatile перед вашим логическим значением блокировки; или еще лучше изучить реальные функции мьютекса, подходящие для вашей платформы.

1
ответ дан 8 December 2019 в 05:21
поделиться

Тот факт, что Thread1 должен быть как можно более быстрым, не означает, что разрешить ему доступ к список, пока он изменяется другим потоком. Поскольку оба потока изменяют список, оба должны ждать. Быстрая скорость не поможет, если в итоге вы получите поврежденные данные.

Изменить:

На самом деле вам может это сойти с рук ... Thread1 только добавляет элементы в список, а Thread2 только удаляет их. Это означает, что Thread1 нужно ждать только в том случае, если список содержит только один элемент.

Edit2:

Таким образом, способ сделать эту работу - для thread2 заблокировать список, если он содержит только один элемент. Это нужно будет проверять перед каждым удалением. Таким образом, потоку thread1 не придется ждать, за исключением этого одного случая.

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

способ сделать эту работу - для thread2 заблокировать список, если он содержит только один элемент. Это нужно будет проверять перед каждым удалением. Таким образом, потоку thread1 не придется ждать, за исключением этого одного случая.

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

способ сделать эту работу - для thread2 заблокировать список, если он содержит только один элемент. Это нужно будет проверять перед каждым удалением. Таким образом, потоку thread1 не придется ждать, за исключением этого одного случая.

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

1
ответ дан 8 December 2019 в 05:21
поделиться

Если вам действительно нужно, чтобы thread1 был как можно быстрее, но при этом требуется безопасность потоков, вы можете предотвратить конфликт блокировок за счет минимальных накладных расходов, как таковых:

std::list<CFoo> g_buffer_thread1;
std::list<CFoo> g_buffer_thread2;
Mutex g_mutex; 

void thread1( CFoo frame ) {
    Locker lock( g_mutex );
    g_buffer_thread1.push_back( frame ) ; 
}


void thread2( )
{
    while( g_buffer_thread2.size() == 0 ) {
        // Wait?
        Locker lock( g_mutex );
        g_buffer_thread1.swap( g_buffer_thread2 );
    }

    while ( g_buffer_thread2.size() > 0 )
    {
        CFoo& pFoo = g_buffer_thread2.front() ;
        // Do something.
        g_buffer_thread2.pop_front();
    }
}

Я думаю, что это наиболее простая комбинация с безопасностью потоков. К сожалению, Thread1 всегда должен блокироваться. Возможно, вам удастся придумать что-то, где вы группируете кадры для thread1. Я предполагаю, основываясь на ваших числах в вопросе, что thread1 выполняется намного больше раз, чем thread2, так что это избавит от некоторых конфликтов блокировки, которые в противном случае возникли бы при использовании только одного списка буферов.

0
ответ дан 8 December 2019 в 05:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: