线程池的使用,以及类的非静态成员函数当作形参传递的问题

在上一篇博客中,实现了线程池类的设计https://blog.csdn.net/kongwei1234/article/details/104664010

由于博主做线程池是为了在Qt编写的应用程序中使用,于是在Qt中新建的窗体程序进行测试,测试时为了获取任务完成时的数据,这里我们可以:
1.利用std::future中的get()成员函数,获取任务的返回值。但是这里用线程池处理的任务耗时大概在200ms左右,且任务生产速度较快,利用get()获取返回值时,在任务完成前,get()所在的线程都会被阻塞,即GUI线程会阻塞住,软件界面就会卡住,这样肯定不行。这里想要处理其实也可以,在创建一个子线程去get()即可,但是设计起来相对麻烦,这里暂时不考虑这种方法。
2.在需要任务函数中,利用Qt的信号与槽的机制,在任务完成时,发送信号,GUI线程中接收信号即可实现。这样做比较简洁,因此这里采用这种办法。

博主定好方法2的思路后,就开始写测试代码了,思路也很简单:
1.首先定义测试需要执行的任务函数:fun()

void MainWindow::fun(int slp){
    qDebug()<<QString("  hello, fun%1 !").arg(slp);
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    qDebug()<<QString("%1 sleep end").arg(slp);
    emit taskComplete(num);
}

fun()函数的功能很简单,即打印提示信息,以及利用延时函数模拟耗时任务,最后再发出信号。
2.然后在MainWindow的构造函数中,利用for循环,提交5000个任务即可。

//线程池对象,定义为类的成员变量,线程数量为10,任务队列最大数量为500
threadpool thrPool(10,500);

//获取任务函数中的数据,需要对信号和槽进行连接
connect(this,SIGNAL(taskComplete(int)),this,SLOT(getSignals(int)),Qt::QueuedConnection);
for(int i=0;i<5000;i++)
{
     thrPool.commit(fun,+1);
}

本以为这样就完成了,然而。。。运行后报错了
原来忽略了类的成员函数不能当作函数形参传入的问题,为什么类的成员函数不能当作形参呢?原来类的成员函数都隐含了一个this指针作为参数,这也是为什么在成员函数内,我们可以持有this指针的原因。在我们将类的成员函数当作形参传入时,由于this指针的原因,参数无法匹配,所以就会报错。
这里该怎么解决这个问题呢,有几种办法:
1.将fun()定义为静态成员函数。但是静态成员函数内没办法访问类的成员,也没法发送信号,因此这里忽略。
2.将fun定义为全局的函数,并定义一个全局的MainWindow指针g_this,在MainWindow构造函数中,将g_this=this;再定义一个专门发射信号的成员函数sendSignal(int num),具体实现如下:

MainWindow *g_this;
void fun1(int slp);
MainWindow::MainWindow(QWidget *parent) :thrPool(10,500),
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(this,SIGNAL(taskComplete(int)),this,SLOT(getSignals(int)),Qt::QueuedConnection);
	for(int i=0;i<5000;i++)
    {
        thrPool.commit(fun1,i+1);
    }
}

void fun1(int slp){
    qDebug()<<QString("  hello, fun%1 !").arg(slp);
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    qDebug()<<QString("%1 sleep end").arg(slp);
    std::unique_lock<std::mutex> lock(g_lock);
    g_this->sendSignal(slp); //这里通过全局的g_this发射信号,等于利用this
}
void MainWindow::sendSignal(int num)
{
    emit taskComplete(num);
}
void MainWindow::getSignals(int num){
    qDebug()<<QString("---------get signals %1---------").arg(num);
}

利用方法2,其实也可以解决方法1的问题。

3.方法2其实已经满足需求了,但是感觉代码不够简洁,看着实在不爽,于是这里采取了一种更加简洁的方式

MainWindow::MainWindow(QWidget *parent) :thrPool(10,500),
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    g_this=this;

    typedef void* (*FUNC)(void*,int);
    FUNC callback = (FUNC)&MainWindow::fun;//强制转换func()的类型
    connect(this,SIGNAL(taskComplete(int)),this,SLOT(getSignals(int)),Qt::QueuedConnection);//
    for(int i=0;i<5000;i++)
    {
        thrPool.commit(callback,this,i+1);
    }

    qDebug()<<"=======get end=======\n";
}
void MainWindow::fun(int slp){
    qDebug()<<QString("  hello, fun%1 !").arg(slp);
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    qDebug()<<QString("%1 sleep end").arg(slp);
    emit taskComplete(num);
}
void MainWindow::getSignals(int num){
    qDebug()<<QString("---------get signals %1---------").arg(num);
}

这样看上去代码就简洁了许多。

4.方法3可以实现,那么利用std::function加上std::bind对成员函数进行绑定,肯定能让程序更加清晰易读,但是这里博主进行了调试,总是报错,还没找到正确的写法,这方法一定可行,等有空再研究吧,有知道的朋友可以告诉博主,感谢!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值