tutorial threads thread librerias libreria library estandar ejemplo clases biblioteca c++ c++11 pthreads mutex

threads - thread library c++



¿Es seguro mezclar las funciones de subprocesos de la biblioteca estándar pthread.h y C++ 11? (4)

¿Puedo generar un hilo con pthread_create y usar std::mutex dentro de forma segura?

Pensaría que si std::mutex se implementa como pthread_mutex_t entonces estaría bien, pero no veo esto documentado en ninguna parte.

Por ejemplo:

#include <pthread.h> #include <mutex> namespace { std::mutex global_lock; } void* thread_func(void* vp) { // std::mutex used in thread spawned with pthread_create std::lock_guard<std::mutex> guard(global_lock); // critical section return nullptr; } int main() { pthread_t tid; pthread_create(&tid, nullptr, thread_func, nullptr); pthread_join(tid, NULL); }

Por cierto estoy ejecutando Debian Wheezy.


No hay ninguna garantía de que funcione, pero es probable que cualquier implementación de C ++ en un sistema operativo que utilice pthreads como su única biblioteca de subprocesos real use pthreads debajo de los subprocesos de C ++, por lo que es probable que funcione.

Es probable que tengas problemas si luego intentas trasladar el código a alguna otra plataforma que use algo que no sea pthreads, incluso si esa plataforma también admite pthreads (por ejemplo, ventanas).

La pregunta es, ¿por qué molestarse y arriesgarse? Si está utilizando C ++ 11 std::mutex , ¿por qué no usa también std::thread ?


Podrías en mi máquina (Debian también). Pero no estoy seguro si llamaría a esto seguro.

Si observa el archivo relevante, /usr/include/c++/4.7/i486-linux-gnu/bits/gthr-default.h en mi caso, verá que habrá una asignación 1: 1 a la api pthreads . <mutex> utiliza __gthread_mutex_lock para el bloqueo que se define exactamente allí para pthread_mutex_lock . O verás que std::thread declara typedef __gthread_t native_handle_type;

No sé si hay una forma documentada de verificar si se utilizan pthreads. Pero gthr-default.h define _GLIBCXX_GCC_GTHR_POSIX_H como include guard y creo que siempre que se defina esta macro, puedes asumir que puedes mezclarlas.

Edición: Dada la sugerencia de @Wakely, escribiría:

template <typename T> using strip = typename std::remove_pointer<typename std::decay<T>::type>::type; static_assert(std::is_same<strip<std::thread::native_handle_type>, pthread_t>::value, "libstdc++ doesn''t use pthread_t");


Si su pregunta es: ¿puedo usar libremente cambiar entre un tipo de exclusión mutua y otro al azar? Entonces la respuesta es no (a menos que todas las capas inferiores utilicen la misma implementación, como pthread_mutex).

Sin embargo, si tiene diferentes grupos de recursos que desea proteger, cualquier grupo de recursos puede protegerse con cualquier implementación. En realidad, a veces puede ser mejor usar un semáforo (es decir, el semáforo es útil para definir un bloqueo para escritura, muchos bloqueos para lecturas).

Entonces, si tiene 4 grupos de recursos que está administrando, puede usar:

  • std :: mutex,
  • pthread_mutex,
  • impulso :: mutex,
  • semáforos.

Lo que no puede hacer es usar boost :: mutex para acceder a datos protegidos por semáforos y viceversa, o std :: mutex para usar elementos protegidos por pthread_mutex.

Como un simple ejemplo, en términos de código, esto significa que un getter y un setter se harían de esta manera:

void set(int new_value) { guard lock(my_mutex); m_value = new_value; } int get() const { guard lock(my_mutex); return m_value; }

Las dos funciones usan el mismo mutex (aquí my_mutex ) y obviamente el mutex tiene un tipo.

Opuesto a eso, no podrías hacer eso:

void set(int new_value) { guard lock(this_mutex_here); m_value = new_value; } int get() const { SafeGuard lock(that_mutex_there); return m_value; }

En este segundo ejemplo, usa dos mutexes diferentes y eso no funcionará como se esperaba porque el bloqueo en set() no bloqueará el bloqueo en get() y viceversa. Así que no hay nada seguro al respecto (incluso si uno de los guardias se llama SafeGuard).

Entonces, la regla es que si protege m_value con un mutex llamado my_mutex , cada vez que acceda a m_value deberá bloquear el my_mytex mutex. No importa la implementación que esté utilizando, siempre y cuando sea consistente de esta manera.


Tanto std::thread como std::mutex tienen un método native_handle que le permite profundizar en la implementación de la plataforma del objeto dado. Esto me dice que la biblioteca de subprocesos estándar está diseñada para funcionar bien con la implementación de la plataforma.

A un lado, std::thread y std::mutex son objetos diferentes que hacen diferentes cosas, a saber. administrar hilos y proporcionar sincronización de subprocesos. Al final, el núcleo hace el trabajo pesado.

Entonces, si no está preocupado por la portabilidad, no puedo ver por qué esto debería ser un problema.

Además, a veces es posible que necesite la implementación de la plataforma nativa para proporcionarle el conjunto de características más rico que permite la plataforma. Por ejemplo, los subprocesos BSD permiten diferentes tipos de subprocesos y algunas bibliotecas de subprocesos le permiten establecer el tamaño de pila de su nuevo subproceso. Las API de subprocesos de C ++ son un denominador común más bajo portátil.