问题
Can I spawn a thread with pthread_create
and use std::mutex
inside of it safely?
I would think that if std::mutex
is implemented as a pthread_mutex_t
then it would be fine but I don't see this documented anywhere
For example:
#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);
}
BTW I'm running Debian Wheezy.
回答1:
You could on my machine (Debian too). But I'm not sure if I would call this safe.
If you look at the relevant file, /usr/include/c++/4.7/i486-linux-gnu/bits/gthr-default.h
in my case, you will see that there will be a 1:1 mapping to the pthreads api. <mutex>
uses __gthread_mutex_lock
for locking which is defined exactly there to pthread_mutex_lock
. Or you will see that std::thread
declares typedef __gthread_t native_handle_type;
I don't know if there is a documented way to check if pthreads are used. But gthr-default.h
defines _GLIBCXX_GCC_GTHR_POSIX_H
as include guard and I think as long as this macro is defined, you can assume that you can mix them both.
Edit: Given the hint from @Wakely, I would write:
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");
回答2:
There's no guarentee in any spec that it will work, but it's likely that any C++ implementation on an OS that uses pthreads as its only real threading library will use pthreads underneath C++ threads, so it will likely work.
You will likely run into problems if you later try to port the code to some other platform that uses something other than pthreads, even if that platform supports pthreads too (eg, windows).
The questions is, why bother and risk it? If you're using C++11 std::mutex
, why not use std::thread
as well?
回答3:
Both std::thread
and std::mutex
have a native_handle
method which allows you to dig down to the platform implementation of the given object. This says to me that the standard threading library is designed to play nice with the platform implementation.
As an aside std::thread
and std::mutex
are different objects that do different things viz. manage threads and provide cross thread synchronization. In the end the kernel does the heavy lifting.
So if you are not worried about portability, I cannot see why this should be an issue.
As an aside, sometimes you may need the native platform implementation so as to provide you with the richer feature-set that the platform allows. For example BSD threading allows different types of threads and some threading libraries allow you to set the stack size of your new thread. The C++ threading APIs are a portable lowest common denominator.
回答4:
If your question is: can I use freely switch between one type of mutex and another at random? Then the answer is no (unless all the bottom layers use the same implementation, such as pthread_mutex.)
However, if you have different groups of resources that you want to protect, any one group of resources can be protected with any one implementation. Actually, it can at times be better to use a semaphore (i.e. semaphore are useful to define a one lock for write, many locks for reads).
So, if you have 4 groups of resources you are managing, you may use:
- std::mutex,
- pthread_mutex,
- boost::mutex,
- semaphores.
What you cannot do is use the boost::mutex to access data protected by the semaphores and vice versa, or std::mutex to use things protected by pthread_mutex.
As a simple example, in terms of code, this means a getter and a setter would be done this way:
void set(int new_value)
{
guard lock(my_mutex);
m_value = new_value;
}
int get() const
{
guard lock(my_mutex);
return m_value;
}
The two functions use the same mutex (here my_mutex
) and obvious the mutex has one type.
Opposed to that, you could not do that:
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;
}
In this second example, you use two different mutexes and that won't work as expected because the lock in set()
won't block the lock in get()
and vice versa. So there is nothing safe about it (even if one of the guards is called SafeGuard.)
So the rule is, if you protect m_value
with a mutex named my_mutex
, any time you access m_value
you must lock the my_mytex
mutex. Which implementation you are using does not matter, as long as you are consistent in this way.
来源:https://stackoverflow.com/questions/15367988/is-it-safe-to-mix-pthread-h-and-c11-standard-library-threading-features