我正在尝试将一个主线程与N个子线程同步。经过一些阅读后,我使用了condition_variable
和unique_lock
。但是,我总是在OS X中收到错误condition_variable::wait: mutex not locked: Operation not permitted
或unique_lock::unlock: not locked: Operation not permitted
。在Linux中,我只获得Operation not permitted
。
更清楚:我的目标是获得一系列印刷品:
main thread, passing to 0
thread 0, passing back to main
main thread, passing to 0
thread 0, passing back to main
...
四个线程中的每一个。
我调整了http://en.cppreference.com/w/cpp/thread/condition_variable中示例中的代码。此示例在unlock
之后使用wait
,并且它只使用除main之外的一个线程(N = 1)。但是当适合使用N> 1线程时,会发生上述错误。
Yam Marcovic在评论中说我不应该使用unlock
。但是,为什么cppreference示例使用它呢?为什么它适用于一个主线程和另一个主线程?
以下是代码:
#include <cstdio>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
constexpr int N_THREADS = 4;
constexpr int N_ITER = 10;
bool in_main[N_THREADS] = {false};
void fun(mutex *const mtx, condition_variable *const cv, int tid){
for(int i=0; i<N_ITER; i++) {
unique_lock<mutex> lk(*mtx);
// Wait until in_main[tid] is false
cv->wait(lk, [=]{return !in_main[tid];});
// After the wait we own the lock on mtx, which is in lk
printf("thread %d, passing back to main\n", tid);
in_main[tid] = true;
lk.unlock(); // error here, but example uses unlock
cv->notify_one();
}
}
int main(int argc, char *argv[]) {
// We are going to create N_THREADS threads. Create mutexes and
// condition_variables for all of them.
mutex mtx[N_THREADS];
condition_variable cv[N_THREADS];
thread t[N_THREADS];
// Create N_THREADS unique_locks for using the condition_variable with each
// thread
unique_lock<mutex> lk[N_THREADS];
for(int i=0; i<N_THREADS; i++) {
lk[i] = unique_lock<mutex>(mtx[i]);
// Create the new thread, giving it its thread id, the mutex and the
// condition_variable,
t[i] = thread(fun, &mtx[i], &cv[i], i);
}
for(int i=0; i < N_ITER*N_THREADS; i++) {
int tid=i % N_THREADS; // Thread id
// Wait until in_main[tid] is true
cv[tid].wait(lk[tid], [=]{return in_main[tid];});
// After the wait we own the lock on mtx[tid], which is in lk[tid]
printf("main thread, passing to %d\n", tid);
in_main[tid] = false;
lk[tid].unlock(); // error here, but example uses unlock
cv[tid].notify_one();
}
for(int i=0; i<N_THREADS; i++)
t[i].join();
return 0;
}
示例输出:
thread 0, passing back to main
main thread, passing to 0
thread 1, passing back to main
thread 0, passing back to main
main thread, passing to 1
thread 2, passing back to main
thread 1, passing back to main
main thread, passing to 2
thread 2, passing back to main
thread 3, passing back to main
main thread, passing to 3
main thread, passing to 0
thread 3, passing back to main
libc++abi.dylib: terminating with uncaught exception of type std::__1::system_error: unique_lock::unlock: not locked: Operation not permitted
Abort trap: 6
答案 0 :(得分:1)
你试图多次qplot(x = p2, y= a3, title="p2 vs a3",
size=I(5), geom="point")+scale_x_log10()
你的互斥体!仔细看看代码:
unlock
其中 for(int i=0; i < N_ITER*N_THREADS; i++) {
int tid=i % N_THREADS; // Thread id
为10且N_ITER
始终为4,因为它们是N_THREADS
我们得到:
constexpr
所以,当 for(int i=0; i < 40; i++) {
int tid=i % 4; // Thread id
i = 0
中的互斥锁被解锁,然后lk[0]
然后再i=4
再次tid = 4%4
并且您再次解锁时!在这种情况下会抛出tid = 0
。
另外,为什么所有这些C-Pointers呢?它不像任何时候任何一个都可以为null。切换到引用..
另外,通常在处理数组索引时,约定是使用std::system_error
而不是size_t
。
答案 1 :(得分:0)
我发现了问题所在。这个问题Using std::mutex, std::condition_variable and std::unique_lock帮助了我。
构建unique_lock
也正在获取unique_lock
。所以必须在调用wait
之前在循环内完成。函数fun
看起来相同,但main
现在看起来像这样:
int main(int argc, char *argv[]) {
// We are going to create N_THREADS threads. Create mutexes and
// condition_variables for all of them.
mutex mtx[N_THREADS];
condition_variable cv[N_THREADS];
thread t[N_THREADS];
// Create N_THREADS unique_locks for using the condition_variable with each
// thread
for(int i=0; i<N_THREADS; i++) {
// Create the new thread, giving it its thread id, the mutex and the
// condition_variable,
t[i] = thread(fun, &mtx[i], &cv[i], i);
// DO NOT construct, therefore acquire, a unique_lock
}
for(int i=0; i < N_ITER*N_THREADS; i++) {
int tid=i % N_THREADS; // Thread id
// Acquire the unique_lock here
unique_lock<mutex> lk(mtx[tid]);
// Wait until in_main[tid] is true
cv[tid].wait(lk, [=]{return in_main[tid];});
// After the wait we own the lock on mtx[tid], which is in lk[tid]
printf("main thread, passing to %d\n", tid);
in_main[tid] = false;
lk.unlock(); // error here, but example uses unlock
cv[tid].notify_one();
}
for(int i=0; i<N_THREADS; i++)
t[i].join();
return 0;
}
唯一的区别是unique_lock
是在循环内部构建的。