1.线程的分离和汇合
c++ 11之后提供了线程类的thread。
线程是通过创建thread 对象进行执行。
这个对象表明了要执行的任务,最简单的是执行一个函数。
线程执行后,与原来的线程保持什么关系。
如下代码:
join()接口,要等thread 对象线程执行完毕,才能够执行原线程。
detach()接口,不用等待原来的线程处理结束,就可以执行原线程,thread 对象被分离,单独执行。
#include <iostream>
#include<thread>
#include <unistd.h>
using namespace std;
void do_something()
{
cout<<"do_something"<<endl;
}
void do_else_something()
{
cout<<"do_else_something"<<endl;
}
class callback_task{
public:
void operator ()()const{
cout<<"callback_task"<<endl;
do_something();
do_else_something();
}
};
int main()
{
callback_task f;
std::thread my_thread(f);
my_thread.join();
std::thread t2([](){
do_something();
do_else_something();
});
t2.detach();
std::cout<<"hellow word"<<endl;
sleep(1);
}
运行结果:
callback_task
do_something
do_else_something
hellow word
do_something
do_else_somethin
2.如何向thread 函数传递参数
如果需要向新的线程函数传递参数,只需要造thread 构造函数中添加更多的参数就可以。
#include <iostream>
#include<thread>
#include<string>
#include <unistd.h>
using namespace std;
void call_back(int n,string const & z)
{
for(int i=0;i<n;i++)
{
cout<<i<<" "<<z<<endl;
}
}
int main()
{
string z{"hi"};
thread mythread(call_back,3,"hello");
mythread.join();
sleep(1);
}
运行结果:
0 hello
1 hello
2 hello
需要注意的是:
线程具备内部储存空间,参数会按照默认的方式,先复制到该处,新创建的执行线程才能进行访问。 即使按引用传递, 新的线程也会复制。
#include <iostream>
#include<stdio.h>
#include<thread>
#include<string>
#include <unistd.h>
using namespace std;
void call_back(int n,string const & z)
{
for(int i=0;i<n;i++)
{
cout<<i<<" "<<z<<endl;
printf("z: %p \n",&z);
}
}
int main()
{
string z{"hi"};
printf("z: %p \n",&z);
thread mythread(call_back,3,z);
mythread.join();
sleep(1);
}
可以看到地质发生了变化
z: 0x7fff48f68b30
0 hi
z: 0x55606ffb0288
1 hi
z: 0x55606ffb0288
2 hi
z: 0x55606ffb0288
按地址传递没有问题,只是将地址传递第副本,毕竟访问的地址指向的值。
#include <iostream>
#include<stdio.h>
#include<thread>
#include<string>
#include <unistd.h>
using namespace std;
void call_back(int n,string * z)
{
for(int i=0;i<n;i++)
{
cout<<i<<" "<<*z<<endl;
printf("z: %p \n",z);
}
}
int main()
{
string z{"hi"};
printf("z: %p \n",&z);
thread mythread(call_back,3,&z);
mythread.join();
sleep(1);
}
结果:
z: 0x7ffe87fbcad0
0 hi
z: 0x7ffe87fbcad0
1 hi
z: 0x7ffe87fbcad0
2 hi
z: 0x7ffe87fbcad0
如何按引用传递呢:
使用:std::ref()
//如何理解呢,c++11 引入的std::bind() 和thread() 的构造函数类似,以及std::ref()函数。
int main()
{
string z{"hi"};
printf("z: %p \n",&z);
thread mythread(call_back,3,std::ref(z));
mythread.join();
sleep(1);
}
z: 0x7ffcb6dccfa0
0 hi
z: 0x7ffcb6dccfa0
1 hi
z: 0x7ffcb6dccfa0
2 hi
z: 0x7ffcb6dccfa0
3. 使用类的成员函数作为线程函数
#include <iostream>
#include<stdio.h>
#include<thread>
#include<string>
#include <unistd.h>
using namespace std;
class X{
public:
void do_something();
};
int main()
{
X m_x;
std::thread t(&X::do_something,&m_x);
t.join();
sleep(1);
}
//如何理解这个构造函数:
将m_x的地址传递给thread 的构造函数,因为新的线程会调用:
&m_x->do_something()。
如果有第三个变量,会将值传递给成员函数作为参数。
4 移动与thread 传递的使用
c++11 加入了移动的概念,将某个对象移动到另一个对象的内部,原来的对象被搬空。
#include <iostream>
#include<stdio.h>
#include<thread>
#include<string>
#include <unistd.h>
using namespace std;
class X{
public:
void do_something();
};
void do_x(unique_ptr<X>);
int main()
{
X m_x;
unique_ptr<X> ptr(new X);
thread my_thread(do_x,std::move(ptr));
my_thread.join();
}
智能指针与移动函数:
当调用thread 的构造函数的时候,std::move(ptr),会将ptr归属权转移到新的线程空间,然后再转移给do_x。
线程分离运行,使用detach()。
RAII 封装线程:
class thread_guard
{
private:
std::thread& t;
public:
explicit thread_guard(std::thread& t_):t(t_)
{
}
~thread_guard()
{
if(t.joinable())
{
t.join();
}
}
thread_guard(thread_guard const &) =delete;
thread_guard& operator = (thread_guard const &) =delete;
};