qt多线程:计算一个积分
qt multithreading: calculating an intergral
我需要使用梯形规则和多线程来计算积分。
我使用的是一个池线程,它是我使用java池线程示例编写的。
#ifndef POOL_H
#define POOL_H
#include <QObject>
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QQueue>
#include "poolworker.h"
#include "segment.h"
class Segment;
class PoolWorker;
class Pool: public QObject
{
Q_OBJECT
public:
explicit Pool(QObject *parent = 0);
Pool(int nThreads);
void execute(Segment *s);
static QWaitCondition con;
static QMutex poolMutex;
static QQueue<Segment*> segmentQueue;
private:
int nThreads;
QVector<PoolWorker*> workers;
};
#endif // POOL_H
#include "pool.h"
QWaitCondition Pool::con;
QQueue<Segment*> Pool::segmentQueue;
QMutex Pool::poolMutex;
Pool::Pool(QObject *parent) :
QObject(parent)
{
}
Pool::Pool(int nThreads)
{
this->nThreads = nThreads;
for (int i = 0; i < nThreads; i++)
{
workers.push_back(new PoolWorker());
workers[i]->start();
}
}
void Pool::execute(Segment *s)
{
poolMutex.lock();
segmentQueue.enqueue(s);
con.wakeOne();
poolMutex.unlock();
}
#ifndef POOLWORKER_H
#define POOLWORKER_H
#include <QThread>
#include <QMutex>
#include "segment.h"
#include "pool.h"
class PoolWorker : public QThread
{
Q_OBJECT
public:
explicit PoolWorker(QObject *parent = 0);
void run();
static QMutex mutex;
signals:
public slots:
private:
};
#endif // POOLWORKER_H
#include "poolworker.h"
QMutex PoolWorker::mutex;
PoolWorker::PoolWorker(QObject *parent) :
QThread(parent)
{
}
void PoolWorker::run()
{
Segment *temp;
forever
{
mutex.lock();
while(Pool::segmentQueue.isEmpty())
{
Pool::con.wait(&mutex);
}
temp = Pool::segmentQueue.dequeue();
mutex.unlock();
temp->doWork();
}
}
每个区间都被放入一个容器"Segment"中,该容器还计算积分Sab = 0.5*(b-a)*(f(a)+f(b))
m = (a+b)/2.0
Sam = 0.5*(m-a)*(f(a)+f(m))
Smb = 0.5*(b-m)*(f(b)+f(m))
如果Sab
和Sam+Smb
之间的差低于Eps
,则我使用Manager::addSum
将Sab
添加到积分和中。如果它不低,我对am
和mb
执行相同的算法。等
#ifndef SEGMENT_H
#define SEGMENT_H
#include <QObject>
#include <cmath>
#include "manager.h"
#include <QDebug>
class Segment : public QObject
{
Q_OBJECT
private:
double a,b,Sab,Sam,Smb,m,Eps;
double f(double x);
public:
explicit Segment(QObject *parent = 0);
Segment(double a, double b);
void doWork();
signals:
public slots:
};
#endif // SEGMENT_H
#include "segment.h"
Segment::Segment(QObject *parent) :
QObject(parent)
{
}
Segment::Segment(double a, double b)
{
this->a = a;
this->b = b;
Eps = 0.001;
}
void Segment::doWork()
{
Sab = 0.5*(b-a)*(f(a)+f(b));
m = (a+b)/2.0;
Sam = 0.5*(m-a)*(f(a)+f(m));
Smb = 0.5*(b-m)*(f(b)+f(m));
if (fabs(Sab - (Sam + Smb)) <= Eps)
{
Manager::addSum(Sab);
qDebug() << "Reached Eps on interval a= " << a << ",b = " << b
<< ", return S+= " << Sab;
Manager::inc();
}
else
{
Manager::threadPool->execute(new Segment(a,m));
Manager::threadPool->execute(new Segment(m,b));
}
}
double Segment::f(double x)
{
return pow(x,3.0) - 4.0*pow(x,2.0) + 6.0*x - 24.0;
}
Manager类将所有内容联系在一起:它创建池,包含总和,并通过在第一个间隔调用池上的execute来启动计算。它还有一个用于调试目的的计数器。
#ifndef MANAGER_H
#define MANAGER_H
#include <QObject>
#include <QThread>
#include <QQueue>
#include <QVector>
#include "segment.h"
#include "pool.h"
class Pool;
class Manager : public QObject
{
Q_OBJECT
private:
static double sum;
static int i;
static QMutex mutex;
public:
explicit Manager(QObject *parent = 0);
static Pool *threadPool;
static void addSum(double add);
static void inc();
double viewSum();
int viewCount();
void doSetup(QThread &thread);
signals:
public slots:
void doWork();
};
#endif // MANAGER_H
#include "manager.h"
double Manager::sum = 0;
int Manager::i = 0;
Pool* Manager::threadPool = new Pool(10);
QMutex Manager::mutex;
Manager::Manager(QObject *parent) :
QObject(parent)
{
}
void Manager::addSum(double add)
{
mutex.lock();
sum += add;
mutex.unlock();
}
void Manager::inc()
{
i++;
}
double Manager::viewSum()
{
return sum;
}
int Manager::viewCount()
{
return i;
}
void Manager::doSetup(QThread &thread)
{
connect(&thread,SIGNAL(started()),this,SLOT(doWork()));
}
void Manager::doWork()
{
threadPool->execute(new Segment(4.5,12.0));
}
我主要创建管理器,为管理器创建一个线程并显示结果。
#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>
#include "manager.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Manager man;
QThread manThread;
man.doSetup(manThread);
man.moveToThread(&manThread);
manThread.start();
manThread.wait(2500);
qDebug() << "integrate(x^3 - 4*x^2 + 6*x - 24) from 4.5 to 12.0 = "
<< man.viewSum();
qDebug() << "i =" << man.viewCount();
manThread.quit();
QTimer::singleShot(1000, &a, SLOT(quit()));
return a.exec();
}
它在大约一半的时间内正确计算积分。另一半我得到的数字比预期的要大(各不相同)。当我得到一个更大的数字时,我注意到一些区间被计算了两次。如果我没有错的话,我已经使代码线程安全了,所以我不明白这是怎么发生的。我对多线程编程还很陌生,所以我可能在互斥方面做了一些错误的事情?或者我从java池的转换是错误的
另一件事是在main.cpp中,我不知道如何正确显示结果,因为我不知道积分何时计算完毕。我在包含管理器的线程上使用了wait(2500)函数,但这不是一个很好的方法,因为不同的PC和不同的函数的计算时间可能不同。
提前感谢您所能提供的任何帮助。
您的锁定错误。在您提到的Java示例中,相同的锁(queue
本身)用于入队(在execute
中)和出队(在工作线程中)。这样,队列操作实际上是线程安全的。不幸的是,在您的代码中,您使用了两个不同的锁。Pool::poolMutex
用于enque(在execute
中)和PoolWorker::mutex
用于deque(在PoolWorker线程中)。这样,您只为线程之间的deque保护队列,但deque和enque可以同时发生。您的Pool::poolMutex
是无用的,因为execute
只被一个线程调用,所以它只被一条线程锁定和解锁。您只需要为enque和deque使用一个相同的互斥对象。通过构造函数将Pool::poolMutex
传递到PoolWorker中,并锁定它而不是PoolWorker::mutex
。
所以,当您查询并且某个线程刚刚完成工作时,它将立即取消查询(因为队列不是空的),而不是等待您的wakeOne
。然后在wakeOne
上,您将启动另一个线程。对于两个线程如何获取同一个作业(而不会崩溃),我没有明确的解释,但如果像Java原始版本中那样只使用一个锁,您的代码肯定会工作得更好。
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 为什么一个向量上的多线程操作很慢
- 全局变量 多读取器 一个写入器多线程安全?
- 一个简单的 win32 多线程代码.这能行吗?
- 具有多线程支持的 RenderClass,将函数调用推送到向量以在另一个线程上调用
- 了解多线程.试图制作一个素数查找器
- C++:一个写入器/多个读取器访问一个unordered_map线程安全
- 为什么我的多线程示例需要与任何一个相同的时间
- 暂停和恢复多线程环境中另一个线程的线程C++技术建议
- 设计一个扩展良好的多线程应用程序
- 我遇到了一个关于多线程的小问题.需要多线程来计算 Pi 和方差
- qt多线程:计算一个积分
- 多线程服务器在一个线程中处理多个客户端
- 多线程-一个作家和一个读者-我们需要使用储物柜吗
- 使用websockettpp库在多线程程序中为endpoint.listen()创建一个单独的提升线程
- 多线程:为什么两个程序比一个程序好
- C++11 多个读取和一个写入线程互斥锁
- 在每个主机线程(多线程 CPU)上创建一个 cuda 流
- 服务器多线程无法保存最后一个套接字描述符
- c++中cppreference中一个多线程示例的解释