C++ 添加作业期间,如果消除了1纳秒的延迟,std线程作业系统将中止
我已经包括了项目的全部来源,只有大约100行。 这是一个多线程作业系统,我正在为一个学校作业而工作,在为此挣扎了几天之后,主要是因为这对我来说都是非常新的(C++11和std线程) 我对thread、mutex和condition_变量类有基本的了解。但是,应用程序会抛出一个调试错误:C++ 添加作业期间,如果消除了1纳秒的延迟,std线程作业系统将中止,c++,multithreading,C++,Multithreading,我已经包括了项目的全部来源,只有大约100行。 这是一个多线程作业系统,我正在为一个学校作业而工作,在为此挣扎了几天之后,主要是因为这对我来说都是非常新的(C++11和std线程) 我对thread、mutex和condition_变量类有基本的了解。但是,应用程序会抛出一个调试错误:R6010 abort()已被调用。当我在向池中添加单个作业的过程中删除1纳秒睡眠调用时。通过在访问和获取作业的过程中放置互斥锁,我希望解决这个错误,但这是徒劳的 #include "stdafx.h" #incl
R6010 abort()已被调用。
当我在向池中添加单个作业的过程中删除1纳秒睡眠调用时。通过在访问和获取作业的过程中放置互斥锁,我希望解决这个错误,但这是徒劳的
#include "stdafx.h"
#include <iostream>
#include <queue>
#include <future>
#include <thread>
#include <atomic>
using namespace std;
float CalcInvSqr(float x){
return (x);
}
class ThreadPool{
public:
ThreadPool::ThreadPool(int numThreads){
for(int i=0;i<numThreads;i++){
threads.push_back(thread(&ThreadPool::StartThread, this));
}
};
ThreadPool::~ThreadPool(){
CleanUp();
}
template<typename F>
future<F> AddJob(std::packaged_task<F()>& job) {
unique_lock<mutex> lock(poolMutex);
this->jobList.push([&job]() {
job();
});
this->cv.notify_one();
lock.unlock();
return job.get_future();
}
void StartThread(){
while(true){
unique_lock<mutex> uLock(poolMutex);
cv.wait(uLock);
if(stopped.load())
return;
std::function<void()> f;
f = jobList.front();
jobList.pop();
uLock.unlock();
f();
}
}
void CleanUp(){
stopped.store(true);
{
unique_lock<mutex> lock(poolMutex);
cv.notify_all();
lock.unlock();
for(int i=0;i<threads.size();i++){
if(threads[i].joinable())
threads[i].join();
}
cout<<jobList.size()<<endl;
}
}
private:
mutable std::queue<std::function<void()>> jobList;
atomic<bool> stopped;
std::vector<std::thread> threads;
std::mutex poolMutex;
std::condition_variable cv;
};
#define JOBS 50
int main(){
ThreadPool pool(4);
std::vector<std::future<float>> results;
for(int i=0;i<JOBS;i++){
std::this_thread::sleep_for(std::chrono::nanoseconds(1));
float num = (float)(rand()%RAND_MAX)/(float)RAND_MAX;
std::packaged_task<float()> task([num](){
return CalcInvSqr(num);
});
results.push_back(pool.AddJob<float>(task));
}
for(int i=0;i<JOBS;i++){
cout<<"VALUE: "<<results[i].get()<<endl;
}
cout<<"Jobs Done ! "<<endl;
system("PAUSE");
return 0;
}
#包括“stdafx.h”
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
浮点数VSQR(浮点数x){
返回(x);
}
类线程池{
公众:
线程池::线程池(int numThreads){
对于(int i=0;ijobst.push([&job])(){
job();
});
此->cv.notify_one();
lock.unlock();
返回工作。获取未来();
}
void StartThread(){
while(true){
唯一锁定锁定(池互斥);
cv.等待(uLock);
if(stopped.load())
返回;
std::函数f;
f=作业列表。前();
jobList.pop();
uLock.unlock();
f();
}
}
空洞清理(){
停止。存储(true);
{
唯一锁(池互斥锁);
cv.通知所有人();
lock.unlock();
对于(int i=0;i让我们分析一下希望线程调用的函数对象会发生什么情况。一步一步:
在main()
任务通过引用传递给AddJob()
在AddJob()
中,任务通过对lambda函数的引用传递
保存引用的lambda函数存储在ThreadPool
对象中,供线程稍后进行计算
AddJob()
返回一个未来,然后将其推送到results
vector
推送完成后,循环块结束,任务
被销毁
如果在将线程推送到线程池::作业列表
和销毁任务
对象之间的短时间内,线程没有处理任务
中的函数,则保存在作业列表
中的函数将保留对无效内存的引用,因为任务
中的函数对象已销毁调用引用的-不再存在-函数的线程失败,导致软件中止
由于std::packaged_task
不可复制,您可能希望移动task
的内容并将其存储在线程池
对象中
另外,仅供参考,额外的延迟对我的Linux机器没有帮助
例子
我修改了两个方法,将打包的_任务
s存储在线程池
对象中。因为打包的_任务
的内容是按值存储和移动的,只有在线程处理完后才会被销毁。请注意emplace
和std::move
在AddJob()
中的使用
模板
未来添加作业(标准::打包的任务和作业){
唯一锁(池互斥锁);
auto future=job.get_future();
这->作业列表.emplace(std::move(job));
此->cv.notify_one();
lock.unlock();
回归未来;
}
void StartThread(){
while(true){
唯一锁定锁定(池互斥);
cv.等待(uLock);
if(stopped.load())
返回;
自动f=std::move(jobList.front());
jobList.pop();
uLock.unlock();
f();
}
}
可变std::队列作业列表;
同样,如凯西在评论中提到的,你应该初始化<代码> thcCult::停止并考虑保护你的代码避免虚假唤醒。在我的系统中,<代码>停止< /COD>被评估为真,所以没有线程正在做他们的作业。< /P> < P>这里是修正的程序。
请注意,在通知条件变量之前,互斥锁已解锁。这一点很重要
您会注意到,我在ThreadPool::Add中使用了一个共享的_ptr。这是因为代码是为c++11编写的。如果是c++14,我们可以取消共享的_ptr,只需将打包的_任务移动到lambda中就可以了
#include <iostream>
#include <queue>
#include <future>
#include <thread>
#include <atomic>
using namespace std;
float CalcInvSqr(float x){
return (x);
}
class ThreadPool{
public:
ThreadPool(int numThreads){
for(int i=0;i<numThreads;i++){
threads.push_back(thread(&ThreadPool::StartThread, this));
}
};
~ThreadPool(){
CleanUp();
}
template<typename F>
std::future<F> AddJob(std::packaged_task<F()> job)
{
auto job_ptr = make_shared<std::packaged_task<F()>>(move(job));
unique_lock<mutex> lock(_job_mutex);
jobList.push_back([job_ptr]() {
job_ptr->operator()();
});
lock.unlock();
_jobs_available.notify_one();
return job_ptr->get_future();
}
void StartThread(){
while (true) {
unique_lock<mutex> job_lock(_job_mutex);
_jobs_available.wait(job_lock, [this]() { return !stopped && !jobList.empty(); });
if (stopped)
return;
auto job = move(jobList.front());
jobList.pop_front();
job_lock.unlock();
job();
}
}
void CleanUp(){
unique_lock<mutex> job_lock(_job_mutex);
stopped = true;
jobList.clear();
job_lock.unlock();
_jobs_available.notify_all();
for (auto& thread : threads) {
if (thread.joinable())
thread.join();
}
}
private:
std::mutex _job_mutex;
std::condition_variable _jobs_available;
std::deque<std::function<void()>> jobList;
atomic<bool> stopped;
std::vector<std::thread> threads;
};
#define JOBS 5000
int main(){
ThreadPool pool(40);
std::vector<std::future<float>> results;
for(int i=0;i<JOBS;i++){
float num = (float)(rand()%RAND_MAX)/(float)RAND_MAX;
std::packaged_task<float()> task([num](){
return CalcInvSqr(num);
});
results.push_back(pool.AddJob<float>(move(task)));
}
for(int i=0;i<JOBS;i++){
cout<<"VALUE: "<<results[i].get()<<endl;
}
cout<<"Jobs Done ! "<<endl;
// system("PAUSE");
return 0;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
浮点数VSQR(浮点数x){
返回(x);
}
类线程池{
公众:
线程池(int numThreads){
对于(int i=0;ioperator());
});
lock.unlock();
_作业可用。通知一个();
return job_ptr->get_future();
}
void StartThread(){
while(true){
唯一锁定作业锁定(\u作业\u互斥体);
_jobs_available.wait(job_lock,[this](){return!stopped&!jobList.empty();});
如果(停止)
返回;
自动作业=移动(jobList.front());
作业列表。pop_front();
job_lock.unlock();
job();
}
}
空洞清理(){
唯一锁定作业锁定(\u作业\u互斥体);
停止=真;
jobList.clear();
job_lock.unlock();
_作业可用。通知所有作业();
用于(自动线程:线程(&T){
if(thread.joinable())
thread.join();
}
}
私人:
std::mutex\u job\u mutex;
std::条件变量可用;
std::德克工作清单;
原子停止;
向量线程;
};
#定义工作5000
int main(){
线程池(40);
std::矢量结果;
对于(int i=0;如果我可以在我的系统上很容易地复制它,+1是一个完整的可编译示例。不过,解决方案……在AddJob
中,
#include <iostream>
#include <queue>
#include <future>
#include <thread>
#include <atomic>
using namespace std;
float CalcInvSqr(float x){
return (x);
}
class ThreadPool{
public:
ThreadPool(int numThreads){
for(int i=0;i<numThreads;i++){
threads.push_back(thread(&ThreadPool::StartThread, this));
}
};
~ThreadPool(){
CleanUp();
}
template<typename F>
std::future<F> AddJob(std::packaged_task<F()> job)
{
auto job_ptr = make_shared<std::packaged_task<F()>>(move(job));
unique_lock<mutex> lock(_job_mutex);
jobList.push_back([job_ptr]() {
job_ptr->operator()();
});
lock.unlock();
_jobs_available.notify_one();
return job_ptr->get_future();
}
void StartThread(){
while (true) {
unique_lock<mutex> job_lock(_job_mutex);
_jobs_available.wait(job_lock, [this]() { return !stopped && !jobList.empty(); });
if (stopped)
return;
auto job = move(jobList.front());
jobList.pop_front();
job_lock.unlock();
job();
}
}
void CleanUp(){
unique_lock<mutex> job_lock(_job_mutex);
stopped = true;
jobList.clear();
job_lock.unlock();
_jobs_available.notify_all();
for (auto& thread : threads) {
if (thread.joinable())
thread.join();
}
}
private:
std::mutex _job_mutex;
std::condition_variable _jobs_available;
std::deque<std::function<void()>> jobList;
atomic<bool> stopped;
std::vector<std::thread> threads;
};
#define JOBS 5000
int main(){
ThreadPool pool(40);
std::vector<std::future<float>> results;
for(int i=0;i<JOBS;i++){
float num = (float)(rand()%RAND_MAX)/(float)RAND_MAX;
std::packaged_task<float()> task([num](){
return CalcInvSqr(num);
});
results.push_back(pool.AddJob<float>(move(task)));
}
for(int i=0;i<JOBS;i++){
cout<<"VALUE: "<<results[i].get()<<endl;
}
cout<<"Jobs Done ! "<<endl;
// system("PAUSE");
return 0;
}