Скажем, у нас есть карта сокетов std :: map, и это многопоточное приложение. На карте будет более одного потока, обращающегося к сокетам для отправки данных сокетов, при этом на карте будет только один поток, обращающийся к сокетам для получения данных, и этот поток также удалит SocketInfo *, если удаленный конец закроется.
В описанной выше ситуации мы можем использовать блокировку чтения-записи (pthread_rwlock_t) для синхронизации потоков? Если да, есть ли у нас больше преимуществ, чем pthread_mutex_t?
Стив
[PSEUDO CODE]
class CSocketIO {
std::map<int, SocketInfo*> m_Sockets; //socket value and socket info
pthread_t m_ReadingSocketThreads; // for reading socket data
};
class CSession {
void SendOutNetworkPackets(); //access sockets for sending sock data
pthread_t m_WorkerThread; // do jobs and send sock data
};
class CSomeClass {
void SendOutNetworkPackets(); // also access sockets
pthread_t m_WorkerThread; // do jobs and send sock data
};
Да, вы можете использовать блокировку чтения / записи для этого, на самом деле это целесообразно.
Преимущество состоит в том, что вы можете иметь несколько одновременных считывателей с блокировкой чтения / записи, тогда как если вы используете простой мьютекс, если один поток читает, другие потоки, которые хотят читать, будут блокироваться, эффективно сериализуя чтения. С блокировкой чтения / записи читатели будут блокировать только тогда, когда происходит запись.
Вы не позволяете двум потокам одновременно записывать в один и тот же сокет, верно? Вы просто хотите защитить поиск SocketInfo*
от map
?
Блокировки читателя-писателя редко бывают полезны, а часто и вредны. Когда у меня есть клиент с недетерминированной ошибкой в многопоточной программе, первый Виновником, которого я ищу, является неправильно используемый замок читателя-писателя. (Вы можете использовать блокировки чтения только для защиты вызовов функций, которые действительно const
.)
Предположительно каждый из ваших потоков делает что-то вроде этого:
// do some work to figure out what to send
SocketInfo* my_socket_info = 0;
// critical section begins here
pthread_mutex_lock(the_map_mutex);
socket_map_t::const_iterator i = m_Sockets.find(id);
if (i != m_Sockets.end()) {
my_socket_info = i->second;
}
pthread_mutex_unlock(the_map_mutex);
// critical section is done
if (my_socket_info != 0) {
// do a bunch of work to actually send the data
// (including acquiring a mutex specific to the socket unless
// you have some other way of guaranteeing that the socket isn't
// currently being written by some other thread)
Второй вопрос, который вам нужно задать (после «это то, что я защищаю на самом деле const
? «) есть: какой процент времени the_map_mutex
заблокирован? Если оно составляет менее 50%, у вас недостаточно разногласий, чтобы заставить читателя заблокировать победу. Вы можете получить хорошую быструю оценку использования критического раздела, защищенного the_map_mutex
измеряя процент времени, которое отдельный поток проводит внутри критической секции, а затем умножая его на количество аппаратных потоков в вашей системе.