C++ C++;线程:在条件_变量等待后无法解锁数组中的互斥锁
我正在尝试将一个主线程与N个子线程同步。经过一些阅读,我使用了C++ C++;线程:在条件_变量等待后无法解锁数组中的互斥锁,c++,multithreading,stl,C++,Multithreading,Stl,我正在尝试将一个主线程与N个子线程同步。经过一些阅读,我使用了condition\u variable和unique\u lock。但是,在OS X中,我总是得到错误条件\u变量::wait:mutex not locked:Operation not allowed或unique\u lock::unlock:not locked:Operation not allowed。在Linux中,我只得到Operation not allowed 更清楚地说:我的目标是获得一系列打印: main t
condition\u variable
和unique\u lock
。但是,在OS X中,我总是得到错误条件\u变量::wait:mutex not locked:Operation not allowed
或unique\u lock::unlock:not locked:Operation not allowed
。在Linux中,我只得到Operation not allowed
更清楚地说:我的目标是获得一系列打印:
main thread, passing to 0
thread 0, passing back to main
main thread, passing to 0
thread 0, passing back to main
...
对于四个线程中的每一个
我根据中的示例改编了代码。本例在wait
之后使用unlock
,并且它只在除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;
}
您多次尝试
解锁
您的互斥锁!仔细查看代码:
for(int i=0; i < N_ITER*N_THREADS; i++) {
int tid=i % N_THREADS; // Thread id
因此,当i=0
时,lk[0]
中的互斥锁被解锁,然后当i=4
时,则tid=4%4
再次tid=0
时,您将再次解锁它<代码>标准::系统错误在这种情况下被抛出
另外,为什么所有这些C指针都是?这并不是说它们中的任何一个在任何时候都可以为空。。切换到引用
另外,通常在处理数组索引时,惯例是使用
size\u t
而不是int
我发现了问题所在。这个问题帮助了我
构造唯一锁
也会获取唯一锁
。因此,它必须在循环内完成,就在调用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;
}
intmain(intargc,char*argv[]){
//我们将创建N_线程。创建互斥体和
//所有的条件变量。
互斥mtx[N_线程];
条件变量cv[N_螺纹];
螺纹t[N_螺纹];
//创建N_线程唯一的_锁,以便将条件_变量用于每个线程
//线
对于(int i=0;iRemovelk[i%4]。首先,从main中解锁()
。您到底想做什么?在执行结束时,您的in_main变量会有什么结果?>删除lk[i%4]。解锁()从main开始,这是产生错误的部分。但是为什么呢?在本例中,等待后您拥有锁,因此需要解锁。这段代码真的很难理解。您可以对其进行注释吗?或者,更好的是,简化它?乍一看,您似乎在两个线程中等待/通知相同的条件变量,或者其他什么你想做什么?我想得到打印的特定顺序。“外线程,迭代n”,其中n%4==m,应该与线程m的打印交替,“内线程m,迭代l”。不同线程的打印之间的顺序并不重要,只是该线程的打印与主线程的相对顺序。谢谢您的回答。但是:“当i=0时,lk[0]中的互斥锁被解锁,然后当i=4时,tid=4%4,所以再次tid=0,您再次解锁!”当i=0时,主线程设置为_main[0]为false。当i=4时,主线程应该在_main[0]中等待再次为真。在继续并再次解锁之前,另一个线程应该更改它。另外,我的印象是,执行条件变量::wait会给线程一个锁定的锁。如果bool修改在锁内,它真的没有定义吗?你说的“另一个线程应该更改它”是什么意思显然不是这样,如果你在_main中设置了防护,那么就没问题了。wait是防护吗?我链接的示例说是,但显然不是。另外,“显然不是”,显然是,看看示例输出。(注意,我将数组初始化为false,因此生成的线程开始打印)很抱歉,这不符合逻辑。我添加了一个编译和运行时获得的示例输出。它似乎通过修改布尔值将控制权交还给了主线程。
for(int i=0; i < 40; i++) {
int tid=i % 4; // Thread id
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;
}