尝试同步队列时发生段错误
Segfault occuring in attempt to synchronize queue
我正在学习多线程,我想模拟生产者-消费者问题(如果可以的话,使用信号量)。
我有一个 class 保存一个队列,生产者将整数推入队列,消费者检索它并打印它。我模拟如下
class TestClass{
public:
void producer( int i ){
unique_lock<mutex> l(m);
q.push(i);
if( q.size() )
cnd.notify_all();
}
void consumer(){
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l);
}
int tmp = q.front();
q.pop();
cout << "Producer got " << tmp << endl;
}
void ConsumerInit( int threads ){
for( int i = 0; i < threads; i++ ){
thrs[i] = thread(&TestClass::consumer, this );
}
for( auto &a : thrs )
a.join();
}
private:
queue<int> q;
vector<thread> thrs;
mutex m;
condition_variable cnd;
};
并且我使用了一个小的控制台应用程序来调用数据:
int main(){
int x;
TestClass t;
int counter = 0;
while( cin >> x ){
if( x == 0 )
break;
if( x == 1)
t.producer(counter++);
if( x == 2 )
t.ConsumerInit(5);
}
}
所以当用户输入 1 时,数据被推入队列,如果用户按下 2 线程被生成。
以任何调用顺序,例如,按 1 1 然后按 2,或 2 1 1
它抛出段错误。我不确定为什么我对我的代码的理解如下:让我们假设顺序 2 1 1
我初始化了5个线程,他们看到队列是空的,所以他们去睡觉了。当我将一个数字推送到队列时,它会通知所有线程休眠。
第一个再次唤醒锁定互斥锁并继续从队列中检索数字然后释放互斥锁,当释放互斥锁时另一个线程执行相同操作并解锁互斥锁,解锁互斥锁后的第三个线程仍在循环中并看到队列再次为空并再次进入休眠状态,与所有剩余线程相同。
这个逻辑对吗?如果是这样,为什么这会不断抛出段错误,如果不是,我感谢所有解释。
感谢您的帮助!
//编辑
根据答案建议,我用 vector.push_back 替换了 [],但消费者现在对数据不做任何事情,不接受或打印它。
当你这样做时你并没有扩展 thrs 向量
thrs[i] = thread(&CTest::consumer, this );
你应该做
thrs.emplace_back(&CTest::consumer, this);
那就是崩溃的地方。
您的问题与多线程无关。您正在访问 std::vector
越界:
for (int i = 0; i < threads; i++) {
thrs[i] = thread(&CTest::consumer, this);
//...
vector<thread> thrs;
thrs
向量为空,您正在尝试访问它,就好像它有条目一样。
要显示错误,请使用:
thrs.at(i) = thread(&CTest::consumer, this);
您将收到 std::out_of_range
异常而不是分段错误。
如果输入序列不是 1 1 1 1 1 ... 2
的形式,你的程序就会死锁。也就是说,如果 1s
前面的数字 2
小于 5。
原因如下:
如果队列大小中的元素总数小于 5 并且主线程调用 consumerInit
,则创建的五个消费者线程中的一些将阻塞等待队列接收元素。同时,主线程阻塞了 join
操作。由于主线程将等待消费者线程完成,而其中一些线程正在等待数据消费,因此不会有任何进展。因此陷入僵局。
问题在这里:
for( auto &a : thrs )
a.join();
在您输入 2
等待消费者完成后,主线程被阻塞在这里。所以在这一点之后你认为你正在输入输入,而没有 cin
发生。
删除这两行然后你可以输入1
和producer/consumer将完成他们的工作。
我正在学习多线程,我想模拟生产者-消费者问题(如果可以的话,使用信号量)。
我有一个 class 保存一个队列,生产者将整数推入队列,消费者检索它并打印它。我模拟如下
class TestClass{
public:
void producer( int i ){
unique_lock<mutex> l(m);
q.push(i);
if( q.size() )
cnd.notify_all();
}
void consumer(){
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l);
}
int tmp = q.front();
q.pop();
cout << "Producer got " << tmp << endl;
}
void ConsumerInit( int threads ){
for( int i = 0; i < threads; i++ ){
thrs[i] = thread(&TestClass::consumer, this );
}
for( auto &a : thrs )
a.join();
}
private:
queue<int> q;
vector<thread> thrs;
mutex m;
condition_variable cnd;
};
并且我使用了一个小的控制台应用程序来调用数据:
int main(){
int x;
TestClass t;
int counter = 0;
while( cin >> x ){
if( x == 0 )
break;
if( x == 1)
t.producer(counter++);
if( x == 2 )
t.ConsumerInit(5);
}
}
所以当用户输入 1 时,数据被推入队列,如果用户按下 2 线程被生成。
以任何调用顺序,例如,按 1 1 然后按 2,或 2 1 1 它抛出段错误。我不确定为什么我对我的代码的理解如下:让我们假设顺序 2 1 1
我初始化了5个线程,他们看到队列是空的,所以他们去睡觉了。当我将一个数字推送到队列时,它会通知所有线程休眠。 第一个再次唤醒锁定互斥锁并继续从队列中检索数字然后释放互斥锁,当释放互斥锁时另一个线程执行相同操作并解锁互斥锁,解锁互斥锁后的第三个线程仍在循环中并看到队列再次为空并再次进入休眠状态,与所有剩余线程相同。
这个逻辑对吗?如果是这样,为什么这会不断抛出段错误,如果不是,我感谢所有解释。
感谢您的帮助!
//编辑 根据答案建议,我用 vector.push_back 替换了 [],但消费者现在对数据不做任何事情,不接受或打印它。
当你这样做时你并没有扩展 thrs 向量
thrs[i] = thread(&CTest::consumer, this );
你应该做
thrs.emplace_back(&CTest::consumer, this);
那就是崩溃的地方。
您的问题与多线程无关。您正在访问 std::vector
越界:
for (int i = 0; i < threads; i++) {
thrs[i] = thread(&CTest::consumer, this);
//...
vector<thread> thrs;
thrs
向量为空,您正在尝试访问它,就好像它有条目一样。
要显示错误,请使用:
thrs.at(i) = thread(&CTest::consumer, this);
您将收到 std::out_of_range
异常而不是分段错误。
如果输入序列不是 1 1 1 1 1 ... 2
的形式,你的程序就会死锁。也就是说,如果 1s
前面的数字 2
小于 5。
原因如下:
如果队列大小中的元素总数小于 5 并且主线程调用 consumerInit
,则创建的五个消费者线程中的一些将阻塞等待队列接收元素。同时,主线程阻塞了 join
操作。由于主线程将等待消费者线程完成,而其中一些线程正在等待数据消费,因此不会有任何进展。因此陷入僵局。
问题在这里:
for( auto &a : thrs )
a.join();
在您输入 2
等待消费者完成后,主线程被阻塞在这里。所以在这一点之后你认为你正在输入输入,而没有 cin
发生。
删除这两行然后你可以输入1
和producer/consumer将完成他们的工作。