Tengo una aplicación multiproceso que crea 48 subprocesos que necesitan acceder a un atributo común (stl :: map). El mapa solo se escribirá cuando comiencen los hilos, y el resto del tiempo se leerá el mapa. Este parece ser el caso de uso perfecto para un pthread_rw_lock, y todo parece estar funcionando bien.¿Cuántos lectores simultáneos puede tener un pthread_rwlock?
Me encontré con un seg-fault completamente no relacionado y comencé a analizar el núcleo. Usando gdb, ejecuté el comando info threads
y me sorprendieron los resultados. Observé que varios hilos estaban realmente leyendo del mapa como se esperaba, pero la parte extraña es que varios hilos fueron bloqueados en pthread_rwlock_rdlock() esperando en el rw_lock.
Aquí es el seguimiento de la pila para un hilo que está esperando en la cerradura:
#0 0xffffe430 in __kernel_vsyscall()
#1 0xf76fe159 in __lll_lock_wait() from /lib/libpthread.so.0
#2 0xf76fab5d in pthread_rwlock_rdlock() from /lib/libpthread.so.0
#3 0x0804a81a in DiameterServiceSingleton::getDiameterService(void*)()
Con tantos hilos, es difícil decir cuántos estaban leyendo y cuántos fueron bloqueados, pero yo no entiendo por qué cualquiera hilos estarían bloqueados esperando a leer, teniendo en cuenta que otros hilos ya están leyendo.
Así que aquí está mi pregunta: ¿Por qué algunos hilos están bloqueados esperando leer un rw_lock, cuando otros hilos ya están leyendo? Parece como si hubiera un límite en la cantidad de hilos que se pueden leer simultáneamente.
Miré las funciones pthread_rwlock_attr_t
y no vi nada relacionado.
El sistema operativo es Linux, SUSE 11.
Aquí está el código relacionado:
{
pthread_rwlock_init(&serviceMapRwLock_, NULL);
}
// This method is called for each request processed by the threads
Service *ServiceSingleton::getService(void *serviceId)
{
pthread_rwlock_rdlock(&serviceMapRwLock_);
ServiceMapType::const_iterator iter = serviceMap_.find(serviceId);
bool notFound(iter == serviceMap_.end());
pthread_rwlock_unlock(&serviceMapRwLock_);
if(notFound)
{
return NULL;
}
return iter->second;
}
// This method is only called when the app is starting
void ServiceSingleton::addService(void *serviceId, Service *service)
{
pthread_rwlock_wrlock(&serviceMapRwLock_);
serviceMap_[serviceId] = service;
pthread_rwlock_unlock(&serviceMapRwLock_);
}
Actualización:
Como se mencionó en los comentarios de MarkB, si hubiera establecido pthread_rwlockattr_getkind_np() para dar prioridad a los escritores, y hay un escritor bloqueado esperando, entonces el comportamiento observado tendría sentido. Pero, estoy usando el valor predeterminado que creo que es dar prioridad a los lectores. Acabo de verificar que hay no hilos bloqueados en espera de escritura. También actualizo el código según lo sugerido por @Shahbaz en los comentarios y obtengo los mismos resultados.
¿Está * seguro * de que no había un bloqueo de bloqueo de escritorios también? –
@MarkB ¡Esa es una excelente pregunta! Pero eso no depende de pthread_rwlockattr_getkind_np() que no he llamado? No estoy seguro de si hay hilos esperando para escribir, pero no deberían ser, ya que eso SOLO debe suceder al principio. Aunque tendré que comprobarlo. – Brady
@MarkB, ¿qué efecto tendría eso si un escritor está esperando y yo no configuré pthread_rwlockattr_getkind_np()? Según tengo entendido, el escritor puede morir de hambre si hay lectores continuos, ¿verdad? – Brady