简介
本文主要介绍标准C++中 thread的创建线程的几种方式。
使用时需要加头文件:
#include <thread>
位于std命名空间中,是跨平台的线程操作
使用说明
1、通过函数指针创建
一般来说,像CreateThread、_beginthread等创建线程时,都会先写一个含有一个参数(LPVOID lpParam)的全局函数,用于通过函数指针创建线程。
在标准C++提供的 thread方法中,函数指针的方式也需要一个全局函数,不过参数个数已经不再受限制
比如
void func(int param1,int param2,int param3);//全局函数
thread t(func,param1,param2,param3);//创建线程
此种方式通过参数的形式传递线程数据
2、通过函数对象创建
通过构建一个函数对象传给thread,以创建线程,因为函数对象的创建方式多样,所以对应创建线程的方式也有多种,具体参照示例代码。
通过函数对象,可以向函数对象类添加成员变量,并初始化和使用这些变量,以传递线程数据
3、通过lamda表达式创建
构建一个lambda表达式创建线程,通过lambda参数传递数据。
4、通过成员函数创建
通过成员函数创建线程,可以在不同的线程中执行对象的方法。在多线程中,如果访问同一个对象,需要保证线程安全,避免竞争条件。
示例代码
#include <iostream>
#include <thread>
using namespace std;
void counter( int id, int numIter )
{
for( int i = 0; i < numIter; ++i )
{
cout << "counter id:" << id << endl;
cout << "iteraion:" << i << endl;
}
}
//通过函数指针创建线程
int main1()
{
thread t1( counter, 1, 6 );
thread t2( counter, 2, 4 );
//如果没有join,main函数加载两个线程后立即结束,导致线程也中止
//可以确保主线程一直运行,直到两个线程都执行完毕
t1.join();
t2.join();
//从不同线程中访问cout是线程安全的,没有任何数据竞争
//即使没有数据竞争,不同线程的输出仍然可以交错(可以通过同步解决)
system( "pause" );
return 0;
}
class CCount
{
public:
CCount( int id, int numIter ): m_ID( id ), mNum( numIter )
{
}
void operator()()const
{
for( int i = 0; i < mNum; ++i )
{
cout << "counter id:" << m_ID << endl;
cout << "iteraion:" << i << endl;
}
}
private:
int m_ID;
int mNum;
};
//通过函数对象创建线程
int main2()
{
//方法1
thread t1{ CCount{1, 20} };
t1.join;
//方法2
CCount c( 2, 12 );
thread t2( c );
t2.join();
//方法3
thread t3( CCount( 3, 10 ) );
t3.join();
system( "pause" );
return 0;
}
//通过lambda创建线程
int main3()
{
int id = 1;
int numIter = 10;
thread t1( [id, numIter]
{
for( int i = 0; i < numIter; ++i )
{
cout << "counter id:" << id << endl;
cout << "iteraion:" << i << endl;
}
} );
t1.join();
system( "pause" );
return 0;
}
class MyClass
{
public:
MyClass( int id = 0, int nNum = 0 ) : m_ID( id ), mNum( nNum )
{
}
~MyClass() = default;
void func()
{
for( int i = 0; i < mNum; ++i )
{
cout << "counter id:" << m_ID << endl;
cout << "iteraion:" << i << endl;
}
}
private:
int m_ID;
int mNum;
};
//通过成员函数创建线程
int main()
{
MyClass mc( 1, 5 );
thread t1( &MyClass::func, &mc );
t1.join();
system( "pause" );
return 0;
}
//#include <cstdlib>
//#include <cstdio>
//#include <cstring>
#include <string>
#include <iostream>
#include <thread>
using namespace std;
#pragma region C++11 thread基本创建方法
#if 1
// 案例一
void my_print()
{
cout << "线程开始执行了!" << " thread ID= " << std::this_thread::get_id() << endl;
//...
//...
cout << "线程结束执行了!" << " thread ID= " << std::this_thread::get_id() << endl;
}
// 案例二
class TA
{
public:
TA()
{
cout << "TA构造函数执行" << this << " thread ID= " << std::this_thread::get_id() << endl;
}
~TA()
{
cout << "~TA析构函数执行" << this << " thread ID= " << std::this_thread::get_id() << endl;
}
// 案例二
void operator()() // 不带参数 必须重载() 因子线程需运行函数
{
cout << "线程operator开始执行了!" << this << " thread ID= " << std::this_thread::get_id() << endl;
//...
//...
cout << "线程operator结束执行了!" << this << " thread ID= " << std::this_thread::get_id() << endl;
}
TA(const TA& ta)
{
cout << "TA拷贝构造函数执行:" << this << " thread ID= " << std::this_thread::get_id() << endl;
}
// 案例四
void thread_fun()
{
cout << "thread_fun执行:" << this << " thread ID= " << std::this_thread::get_id() << endl;
}
};
int main()
{
// 案例一 直接用函数当对象
//std::thread thobj(my_print);
thobj.join();
//bool b = thobj.joinable();
//thobj.detach();
//b = thobj.joinable();
// 案例二 直接用类对象当对象
TA t;
//std::thread thobj2(t);
std::thread thobj2(std::ref(t)); // 注意这两种的区别 std::ref直接引用原对象,少了一次拷贝和析构
thobj2.join(); // 此时子线程拷贝的对象 析构函数会在前台运行
//thobj2.detach(); // 此时子线程拷贝的对象 析构函数会在后台运行
// 案例三 lambda表达式
//auto my_thread = [] {
// cout << "lambda线程开始执行了!" << endl;
// //...
// //...
// cout << "lambda线程结束执行了!" << endl;
//};
//auto my_thread1 = []()->void {
// cout << "lambda线程开始执行了!" << endl;
// //...
// //...
// cout << "lambda线程结束执行了!" << endl;
//};
//std::thread thobj3(my_thread);
//thobj3.join();
//std::thread thobj4([] {
// cout << "lambda线程开始执行了!" << endl;
// //...
// //...
// cout << "lambda线程结束执行了!" << endl;
//});
//thobj4.join();
//案例四 使用类成员函数作为线程函数
//TA t;
//std::thread thobj5(&TA::thread_fun, &t);
//thobj5.join();
printf("hello jadeshu...\n");
//system("pause");
return 0;
}
#endif
#pragma endregion C++11 thread基本创建方法
#pragma region 线程传参实例应用
//void my_print(const int num, const string &buf)
//{
// cout << num << endl;
// cout << buf << endl;
//}
//
//int main()
//{
// //一、传递临时对象作为线程参数
// int var = 20;
// int& my_var = var;
// char my_buf[] = "this is main.cpp";
// std::thread thobj1(my_print,my_var,string(my_buf));
// thobj1.detach();
// //thobj1.join();
//
// printf("hello jadeshu...\n");
// //system("pause");
// return 0;
//}
#pragma endregion 线程传参实例应用
// 函数调用操作符的声明与定义.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <thread> //用于管理线程的函数和类在<thread>中声明,而那些保护共享数据的函数和类在其它头文件中声明.
using namespace std;
void do_something()
{//每个线程都必須具有的一个初始函数(initial fun)
std::cout << "do_something()\n";
}
void do_something_else()
{//每个线程都必須具有的一个初始函数(initial fun)
std::cout << "do_something_else()\n";
}
class background_task
{
public:
void operator()() const
{ //函数调用操作符的声明与定义
do_something();
do_something_else();
}
};
//通过成员函数创建线程
class MyClass
{
public:
MyClass(int id = 0, int nNum = 0) :m_ID(id),mNum(nNum)
{
}
~MyClass() = default;
void func()
{
for (int i = 0; i < mNum; ++i)
{
cout << "counter id:" << m_ID << endl;
cout << "iteraion:" << i << endl;
}
}
private:
int m_ID;
int mNum;
};
int _tmain(int argc, _TCHAR* argv[])
{
background_task f;
std::thread my_thread(f);//my_thread(f),将一个带有函数调用操作符的类的实例传递给std::thread的构造函数,是一个经常使用的编程实践.
my_thread.join();
MyClass mc(1, 5);
thread t1(&MyClass::func,&mc);
t1.join();
system("pause");
return 0;
}