У меня есть несколько буферов, совместно используемых несколькими потоками чтения / записи, и разные писатели изменяют данные по-разному.
Например, Writer1 просто добавляет новые данные, а Writer2 увеличивает размер буфера (перераспределяет память и перемещает данные).
Если я поставлю один мьютекс для синхронизации всех обращений к данным, производительность может быть не лучше, потому что большинству читателей просто нужно читать один буфер, а большинству писателей просто нужно записать небольшой фрагмент данных в один буфер.
Если я подготовлю один мьютекс для каждого буфера, отношения блокировки / разблокировки между потоками будут более сложными.
Теперь я хочу кое-что подтвердить:
Если писатель изменяет данные только с помощью shared_lock на мьютексе, будут ли другие видеть грязные данные с unique_lock / shared_lock на том же мьютексе?
Я закодировал экспериментальную программу, как показано ниже, и она выглядит безошибочной, но я все еще не осмеливаюсь использовать ее в продукте.
atomic_bool g_abShouldRun = true;
sem_t g_semDoIt1;
sem_t g_semDone1;
sem_t g_semDoIt2;
sem_t g_semDone2;
shared_mutex g_mutex;
int g_iX = 3, g_iY = 9, g_iR1 = 1, g_iR2 = 3;
void writer() {
std::srand( 8 );
while( g_abShouldRun ) {
sem_wait( &g_semDoIt1 );
while( rand() % 8 != 0 )
;
{
shared_lock<shared_mutex> lk( g_mutex );
g_iX *= 2;
g_iY *= 2;
}
sem_post( &g_semDone1 );
};
};
void reader() {
std::srand( 8 );
while( g_abShouldRun ) {
sem_wait( &g_semDoIt2 );
while( rand() % 8 != 0 )
;
{
unique_lock<shared_mutex> lk( g_mutex );
g_iR1 = g_iX;
g_iR2 = g_iY;
}
sem_post( &g_semDone2 );
};
};
int main( int argc, char** argv ) {
int iLasting = 10, iError = 0;
if( argc > 1 )
iLasting = atoi( argv[1] );
steady_clock::time_point tpEnd = steady_clock::now() + seconds( iLasting );
if( sem_init( &g_semDoIt1, 0, 0 ) || sem_init( &g_semDone2, 0, 0 ) ||
sem_init( &g_semDoIt2, 0, 0 ) || sem_init( &g_semDone2, 0, 0 ) ) {
cerr << "Failed to create semaphors." << endl;
return EXIT_FAILURE;
}
thread thd1( writer );
thread thd2( reader );
while( steady_clock::now() < tpEnd ) {
sem_post( &g_semDoIt1 );
sem_post( &g_semDoIt2 );
sem_wait( &g_semDone1 );
sem_wait( &g_semDone2 );
if( g_iR1 * 3 != g_iR2 )
++iError;
}
g_abShouldRun = false;
sem_post( &g_semDoIt1 );
sem_post( &g_semDoIt2 );
thd1.join();
thd2.join();
sem_destroy( &g_semDoIt1 );
sem_destroy( &g_semDoIt2 );
sem_destroy( &g_semDone1 );
sem_destroy( &g_semDone2 );
cout << "Error:" << iError << endl;
return EXIT_SUCCESS;
};