同时为队列中的对象执行函数时出现奇怪的行为
strange behavior in concurrently executing a function for objects in queue
我的程序有一个共享queue
,主要分为两部分:
一个用于将类request
的实例推送到queue
,另一个用于访问queue
中的多个request
对象并处理这些对象。 request
是一个非常简单的类(仅用于测试),具有string req
字段。
我正在研究第二部分,这样做,我想保留一个scheduling thread
,以及多个(在我的示例中,两个)executing threads
。
我想有一个单独的scheduling thread
的原因是减少lock
的数量,并通过多个executing threads
unlock
访问queue
的操作。
我正在使用 pthread 库,我的调度和执行函数如下所示:
void * sched(void* elem) {
queue<request> *qr = static_cast<queue<request>*>(elem);
pthread_t pt1, pt2;
if(pthread_mutex_lock(&mut) == 0) {
if(!qr->empty()) {
int result1 = pthread_create(&pt1, NULL, execQueue, &(qr->front()));
if (result1 != 0) cout << "error sched1" << endl;
qr->pop();
}
if(!qr->empty()) {
int result2 = pthread_create(&pt2, NULL, execQueue, &(qr->front()));
if (result2 != 0) cout << "error sched2" << endl;
qr->pop();
}
pthread_join(pt1, NULL);
pthread_join(pt2, NULL);
pthread_mutex_unlock(&mut);
}
return 0;
}
void * execQueue(void* elem) {
request *r = static_cast<request*>(elem);
cout << "req is: " << r->req << endl; // req is a string field
return 0;
}
简单地说,execQueue
每个线程都有一个要执行的线程,并且只是输出通过void* elem
参数传递给它的请求。
sched
在 main()
中调用,带有一个线程,(如果您想知道如何调用,它会在main()
中调用,如下所示)
pthread_t schedpt;
int schresult = pthread_create(&schedpt, NULL, sched, &q);
if (schresult != 0) cout << "error sch" << endl;
pthread_join(schedpt, NULL);
并且 sched
函数本身创建多个(此处为两个)executing threads
并从queue
pop
s request
s,并通过在多个线程上调用 execQueue
(pthread_create然后ptrhead_join)来执行 request
s。
问题是程序的奇怪行为。
当我检查队列中的大小和元素而不创建线程并在多个线程上调用它们时,它们正是我所期望的。
但是,当我使用多个线程运行程序时,它会打印出来
队列中有 1 个项目。队列中有 2 个项目。要求是:要求是:第一!(x' j|1 rj|p rj|1 FIRST! ' j|!' j| ' j|P ( ( (1 i|p i|
最后一行不断变化。
所需的输出为
队列中有 1 个项目。队列中有 2 个项目。要求是:第一要求是:第一
我想要么我在多个线程上调用execQueue
的方式,要么我pop()
的方式是错误的,但我无法找出问题所在,也找不到任何来源来参考正确的用法。
请帮我解决这个问题。请耐心等待我笨拙地使用 pthread,因为我是初学者。
您的队列包含对象,而不是指向对象的指针。您可以按原样通过operator &()
对队列前面的对象进行寻址,但是一旦弹出队列,该对象就消失了,该地址不再有效。当然,sched
不在乎,但您发送该地址的execQueue
功能肯定会在乎。
对代码最直接的修复是:
更改此设置:
pthread_create(&pt1, NULL, execQueue, &(qr->front()));
对此:
// send a dynamic *copy* of the front queue node to the thread
pthread_create(&pt1, NULL, execQueue, new request(qr->front()));
并且您的线程进程应更改为:
void * execQueue(void* elem)
{
request *r = static_cast<request*>(elem);
cout << "req is: " << r->req << endl; // req is a string field
delete r;
return nullptr;
}
也就是说,我可以想到更好的方法来做到这一点,但这应该解决你的直接问题,假设你的request
对象类是可复制构造的,如果它有动态成员,则遵循三法则。
您温和消毒的c ++ 11版本,因为我需要一个简单的测试来安装MSVC2013:)
在科里鲁现场观看
#include <iostream>
#include <thread>
#include <future>
#include <mutex>
#include <queue>
#include <string>
struct request { std::string req; };
std::queue<request> q;
std::mutex queue_mutex;
void execQueue(request r) {
std::cout << "req is: " << r.req << std::endl; // req is a string field
}
bool sched(std::queue<request>& qr) {
std::thread pt1, pt2;
{
std::lock_guard<std::mutex> lk(queue_mutex);
if (!qr.empty()) {
pt1 = std::thread(&execQueue, std::move(qr.front()));
qr.pop();
}
if (!qr.empty()) {
pt2 = std::thread(&execQueue, std::move(qr.front()));
qr.pop();
}
}
if (pt1.joinable()) pt1.join();
if (pt2.joinable()) pt2.join();
return true;
}
int main()
{
auto fut = std::async(sched, std::ref(q));
if (!fut.get())
std::cout << "error" << std::endl;
}
当然,它现在实际上并没有做太多事情(因为队列中没有任务)。
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 按对象的特定方法按升序排列的C++优先级队列
- 将 RTOS 队列对象封装在仅具有静态分配的 IQueue 自定义接口中
- 具有非 POD 对象的 GLib 异步队列
- 从队列返回对象的最快方法,但前提是队列有它
- 队列未添加对象-C++11
- 如何在BFS(C++)期间删除队列中的对象
- 为什么STL优先级队列错误地分配了我的类对象
- 弹出后,C++队列是否会销毁对象?
- 具有自定义对象的C 优先级队列
- 在优先级队列被推送到队列后,如何编辑对象成员
- 是否可以更改在优先级队列中添加具有相同优先级的"side"对象?
- C++ std::队列推送弹出两个不同的对象获取第一个对象
- C++使用对象的优先级队列
- 意外C++队列行为,弹出后丢失对象
- 无法修改数组中对象的队列
- 为什么为我的对象类编译标准优先级队列失败
- 将队列项目复制到另一个类对象中
- 使用提升线程监视对象队列
- 在c++中,在两个进程之间拥有无限对象队列的最佳方式