|
引言
C++11 引入了 thread 类,降低了使用多线程的复杂度,原先使用多线程只能用系统的 API,无法解决跨平台问题,代码平台的改变,对应多线程代码也必须要修改。
在 C++11 中只需使用语言层面的 thread 可以解决这个问题。编写并发程序需引入头文件<thread>。1线程库
管理当前线程的函数,定义于thread1.2构造函数和赋值
构造函数 | 功能 | thread() ; | ①默认构造函数,构造不表示线程的新 thread 对象 | thread( thread&& other ); | ②移动构造函数。构造表示曾为 other 所表示的执行线程的 thread 对象。此调用后 other 不再表示执行线程。 | template< class Function, class… Args >explicit thread( Function&& f, Args&&… args ); | ③初始化构造函数;构造新的 std::thread 对象并将它与执行线程关联。 | 拷贝构造函数被禁用,std::thread 对象不可拷贝构造,也不可以赋值。
1.2.1初始化构造函数和默认构造函数的使用
#include <iostream>
#include <thread>
using namespace std;
void threadfun(int a)//值传递
{
cout << &#34;threadfun: &#34; << endl;
cout << a << endl;
}
int main()
{
// ①默认构造函数,构造不表示线程的新 thread 对象(很少使用)
thread th1();
//③构造新的 std::thread 对象并将它与执行线程关联。
thread th3(threadfun, 3);//创建 std::thread 执行对象,线程调用 threadFun 函数,函数参数为 args。
cout << &#34;main end&#34; << endl;
th3.join();//使th3线程执行完毕(可尝试挪动这条语句位置,观察结果)
return 0;
}

1.2.2移动构造函数的使用
#include <iostream>
#include <thread>
using namespace std;
void threadfun(int a)//值传递
{
cout << &#34;threadfun: &#34; << endl;
cout << a << endl;
}
int main()
{
//③构造新的 std::thread 对象并将它与执行线程关联。
thread th3(threadfun, 3);
thread th2(std::move(th3));//移动构造函数(th3线程失去所有权)
cout << &#34;main end&#34; << endl;
th2.join();
return 0;
}

1.3成员函数
成员函数 | 功能 | std::thread::id get_id() ; | :获取线程 ID,返回类型 std::thread::id 对象。 | void join(); | 创建线程执行线程函数,调用该函数会阻塞当前线程,直到线程执行完 join 才返回。 | void detach(); | 从 thread 对象分离执行线程,允许执行独立地持续。一旦该线程退出,则释放任何分配的资源。detach 调用之后,目标线程就成为了守护线程,驻留后台运行,与之关联的 std::thread 对象失去对目标线程的关联,无法再通过 std::thread 对象取得该线程的控制权。 | bool joinable() const ; | 检查 std::thread 对象是否标识活跃的执行线程。 | void swap( std::thread& other ) ; | 交换二个 thread 对象的底层柄。 | static unsigned int hardware_concurrency() ; | 返回实现支持的并发线程数。 | #include <iostream>
#include <thread>
using namespace std;
void threadfun(int &a)//引用
{
cout << &#34;threadfun: &#34; << endl;
cout << &#34;thread id: &#34; << std::this_thread::get_id << endl;
cout <<&#34;a = &#34;<< (a += 10 )<< endl;
}
int main()
{
int a = 3;
int b = 5;
cout << &#34;支持的并发线程数: &#34; << std::thread::hardware_concurrency() << endl;
thread th1(threadfun, std::ref(a));
thread th2(threadfun, std::ref(b));
cout << &#34;th1.get_id: &#34; << th1.get_id() << endl;
cout << &#34;th2.get_id: &#34; << th2.get_id() << endl;
cout << &#34;after starting: &#34; << th1.joinable() <<endl;
th1.join();
cout << &#34;after join: &#34; << th1.joinable() << endl;
cout << &#34;main end&#34; << endl;
th2.join();
return 0;
}

1.4拓展:.创建建线程,线程函数为类成员函数
#include <iostream>
#include <thread>
using namespace std;
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x)
{
cout << &#34;Constructor Object: &#34; << this << endl;
}
~Object()
{
cout << &#34;Destroy Object: &#34; << this << endl;
}
void fun(string info)
{
cout << info << value << endl;
}
};
int main()
{
Object obj;
string str = &#34;我是一个类的成员函数!&#34;;
thread t1(&Object::fun, &obj, str);
t1.join();
return 0;
}

2.管理当前线程的函数(定义于命名空间 this_thread)
管理当前线程的函数 | 功能 | void yield() ; | 建议实现重新调度各执行线程,可以将本线程的 CPU 时间片放弃,并允许其他线程运行。 | template< class Rep, class Period >void sleep_for( const std::chrono::duration& sleep_duration ); | 阻塞当前线程执行,至少经过指定的 sleep_duration 。(使当前线程的执行停止指定的时间段) | template< class Clock, class Duration >void sleep_until( const std::chrono::time_point& sleep_time ); | 阻塞当前线程,直至抵达指定的 sleep_time | get_id函数已描述;
yield 方法其实就是::Sleep(0)。
Sleep会交出CPU时间片,允许其他线程运行,但“其他线程”也包含了交出 CPU 时间片的那个线程。
想要更好的进行线程切换,不能够使用 Sleep,而应采用线程锁或其他线程切换方法。
#include <iostream>
#include <thread>
using namespace std;
void threadfun(int &a)//引用
{
std::this_thread::sleep_for(std::chrono::milliseconds(200));
cout << &#34;threadfun: &#34; << endl;
cout <<&#34;a = &#34;<< (a += 10 )<< endl;
}
int main()
{
int a = 3;
int b = 5;
thread th1(threadfun, std::ref(a));
thread th2(threadfun, std::ref(b));
cout << &#34;main &#34; << endl;
th1.join();th2.join();
return 0;
}

3.多线程获取返回值方法
在 C++11 多线程中 std::thread 对象会忽略顶层函数的返回值。
但是在许多时候,我们想要得到线程返回的值。那么该如何操作?
3.1 方法1(指针法)
#include <iostream>
#include <thread>
using namespace std;
//线程返回值 = 形参1 + 形参2
void threadfun(int a, int b, shared_ptr<int> add)
{
*add = a + b;
}
int main()
{
int a = 3;
int b = 5;
shared_ptr<int> add(new int(0));
cout << &#34;before add: &#34; << *add << endl;
thread th1(threadfun, a,b,add);
th1.join();//等待th1线程运行完毕
cout << &#34;after add: &#34; << *add << endl;
return 0;
}

3.2 方法2(使用std::future(期望)和std::promise(承诺)来取数据)
std::future和std::promise是封装好的两个类模板,这两个类需要配合使用,它们的头文件是<future>,
唯一期望(std::future)的实例只能与一个指定事件相关联。
共享期望(std::shared_future<>)的实例就能关联多个事件。
std::future,表示存储着一个未来会被初始化的变量。这个变量可以通过std::future提供的成员函数std::future::get()来得到。如果在这个变量被赋值之前有别的线程试图通过std::future::get()获取这个变量,那么这个线程将会被阻塞到这个变量可以获取为止。
std::promise同样也是一个类模板,这个对象承诺在未来一定会初始化一个变量(std::future中的变量),每一个std::promise对象都有一个与之关联的std::future对象。当std::promise设置值的时候,这个值就会赋给std::future中的对象了。 |
|