当线程函数为C++类成员函数时

来源:互联网 发布:西门子工控软件 编辑:程序博客网 时间:2024/05/11 04:14

很多时候我们在C++多线程开发时,都会或多或少遇到线程函数为C++类中的某个成员函数,此时可能会发生什么呢?你有可能会杂么做呢?
接下来我就为大家总结一下我在这方面走过的一个历程

1.问题一

记得我在之前在写一个udp传输文件的程序时,我就第一次遇到了线程函数为C++类的成员函数,当时遇到的问题,大概意思如下:

#include<iostream>#include <thread>#include <unistd.h>class Test{    public:        Test():testThread_(print)        {        }        void print(void)        {            std::cout<<"hello"<<std::endl;        }    private:        std::thread testThread_;};int main(int argc,char **argv){  Test test;  sleep(1000);   return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

如上述代码,当我编译时会产生如下编译结果
这里写图片描述
根据第一个error报错,貌似程序希望我们把print函数设为静态函数,第二个error则意思是我们传递的参数不能和std::thread所匹配。我的前几篇博文有写过std::thread相关的知识,它的第一个参数为函数指针,而我们的标准C++里这样是获取不到其成员函数的指针的所以才会产生上述的报错。关于C++获取其成员函数方面的知识,请参考这个链接http://www.zhihu.com/question/27738023

2.(一)解决方案

根据一种的报错,我想我们想到的最简单的方法就是把成员函数设成静态成员函数
具体如下

#include<iostream>#include <thread>#include <unistd.h>class Test{    public:        Test():testThread_(print)        {        }        static void print(void)        {            std::cout<<"hello"<<std::endl;        }    private:        std::thread testThread_;};int main(int argc,char **argv){  Test test;  sleep(1000);   return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

这个代码解决了我在一中遇到的问题

3.问题二

2中似乎表面上解决了我的问题,但事实上由于2的解决方案,我又遇到了新的问题

#include<iostream>#include <thread>#include <unistd.h>class Test{    public:        Test(int m):n(m),testThread_(print)        {        }        static void print(void)        {            std::cout<<n<<std::endl;        }    private:        int n;        std::thread testThread_;};int main(int argc,char **argv){  Test test(8);  sleep(1000);   return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在上述代码中,当我的线程函数在使用类的成员函数时,编译时会报错
这里写图片描述
这是因为,我们的静态成员函数并不能使用非静态的成员变量(因为它没有某个具体对象的this指针)

4.(二)解决方案1

解决方案很简单,我们只需给静态成员函数传递某对象的this指针即可
具体如下

#include<iostream>#include <thread>#include <unistd.h>class Test{    public:        Test(int m):n(m),testThread_(print,this)        {        }        static void print(Test *pt)        {            std::cout<<pt->n<<std::endl;        }    private:        int n;        std::thread testThread_;};int main(int argc,char **argv){  Test test(8);  sleep(1000);   return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

5.(二)解决方案2

4中的确完全解决了我们在线程中调用类的成员函数的所有问题,但是你会不会感觉其用起来很别扭,本来我们只是向使一个成员函数为线程函数,这样我们就可以在该线程函数中直接使用该类的成员变量了,但是由于2中有叙述的那些原因,结果使我们不得不使用将成员函数设为静态的,结果就是我们现在使用类的成员变量会这么麻烦,感觉好不爽。难道就没什么方法可以让我们不是成员函数变为静态的?
哈哈,当然是有的具体方案如下

#include<iostream>#include <thread>#include <unistd.h>#include <functional>class Test{    public:        Test(int m):n(m),testThread_(std::bind(&Test::print,this))        {        }        void print(void)        {            std::cout<<n<<std::endl;        }    private:        int n;        std::thread testThread_;};int main(int argc,char **argv){  Test test(8);  sleep(1000);   return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

我们可以像上述代码那样只需用C++11新标准的std::bind函数将其成员函数与对应的对象指针(即this指针)绑定之后便可高枕无忧的解决我们上述的所有问题了