#include
#include // 包含多线程相关声明的头文件
// 普通函数
void hello()
{
std::cout << "Hello Concurrent World!" << std::endl;
}
// main线程
int main()
{
std::thread t(hello); // 将一个普通函数作为std::thread对象的构造参数启动新线程
t.join(); // 在main线程中等待t对象关联的线程结束
return 0;
}
#include
#include
class Test
{
public:
void operator()() // 重载()运算符
{
std::cout << "Hello World!" << std::endl;
}
};
// main线程
int main()
{
Test test; // 构造一个可调用对象
std::thread t(test); // 将一个可调用对象作为std::thread对象的构造参数启动新线程
t.join(); // 在main线程中等待t对象关联的线程结束
return 0;
}
#include
#include
// main线程
int main()
{
std::string str = "Hello World!"; // 在main线程中定义了字符串str
std::thread t([=]() { // 使用lambda表达式构造thread类,并使用main线程中的字符串str
std::cout << str << std::endl;
});
t.join(); // 使main线程等待新线程结束
return 0;
}
#include
#include
// 子线程程序:向父线程问好
void hello()
{
std::cout << "Hello Father!" << std::endl;
}
// main线程
int main()
{
std::thread t(hello); // 发起子线程
std::cout << "Hello Son!" << std::endl; // 向子线程问好
t.join(); // 等待子线程结束,此代码执行完毕后父子线程“汇合”
return 0;
}
#include
#include
#include // 使用其包含的Sleep函数
// 子线程程序:不停打印更大的数字
void hello()
{
int i = 0;
while (1)
{
std::cout << i++ << std::endl;
Sleep(10); // 打印慢一点,不然截屏只能看到一者线程的输出
}
}
// main线程
int main()
{
std::thread t(hello); // 发起子线程
t.detach(); // 分离子线程(子线程与t解除关联)
t.~thread(); // 析构未关联线程的thread对象t
while (1) // 父线程:打印1
{
std::cout << 1 << std::endl;
Sleep(10);
}
return 0;
}
#include
#include
class func
{
public:
int& i;
func(int& _i) :i(_i) {}
void operator()() // 子线程
{
for (int j = 0; j < 10000000000; j++)
{
std::cout << i << std::endl;
}
}
};
void oops()
{
int k = 0;
func my_func(k);
std::thread t(my_func); // 发起新线程
t.detach(); // 分离新线程
}
// main线程
int main()
{
oops();
while (1);
return 0;
}
#include
#include
void f()
{
std::thread t; // 发起子线程
try
{
// 父线程程序
}
catch (const std::exception&)
{
t.join(); // 如果检测到异常也执行汇合或分离,保证t析构不会报错
}
t.join(); // 如果没有检测到异常,正常执行汇合或分离
}
// main线程
int main()
{
f();
return 0;
}
#include
#include
// 使用类存储thread对象
class thread_guard
{
public:
std::thread& t; // 记录thread对象
explicit thread_guard(std::thread& t_) :t(t_) {} // 构造函数
~thread_guard() // 析构函数,会使其记录thread对象可能关联的线程汇合或分离
{
if (t.joinable())
{
t.join();
}
}
thread_guard(thread_guard const&) = delete; // 禁用拷贝构造
thread_guard& operator=(thread_guard const&) = delete; // 禁用赋值
};
void f()
{
std::thread t;
thread_guard tg(t);
// 父线程程序
}
// main线程
int main()
{
f();
return 0;
}
#include
#include
// 一个带参的函数
void print(std::string i)
{
std::cout << i << std::endl;
}
// main线程
int main()
{
std::string str = "Learn DirectX So Cool!";
// 构造thread对象并传入可调用对象以及其参数,线程就被发起
std::thread t(print,str);
// 等待子线程
t.join();
return 0;
}
#include
#include
// 带有引用参数的可调用对象
void print(int& i)
{
std::cout << i << std::endl;
}
// main线程
int main()
{
int i = 0;
// 向构造函数中传入可调用对象和对应参数
std::thread t(print, i);
t.join();
return 0;
}
#include
#include
// 可调用对象的参数类型为const int&
void print(const int& i)
{
// 在新线程中查看其地址
std::cout << &i << std::endl;
}
// main线程
int main()
{
int i = 0;
std::thread t(print, i);// 发起新线程
std::cout << &i << std::endl; // 在main线程中查看变量地址
t.join();
return 0;
}
#include
#include
void print(int& i)
{
// 在新线程中查看其地址
std::cout << &i << std::endl;
}
// main线程
int main()
{
int i = 0;
std::thread t(print, std::ref(i));// 发起新线程
std::cout << &i << std::endl; // 在main线程中查看变量地址
t.join();
return 0;
}
#include
#include
class X
{
public:
int i = 1;
void print() // 类内成员函数
{
std::cout << i << std::endl;
}
};
void test()
{
X my_x;
// 以类内成员函数为可调用对象,需要传入成员函数指针和类实例地址
std::thread t(&X::print, &my_x);
t.join();
}
// main线程
int main()
{
test();
return 0;
}
#include
#include
void print(std::unique_ptr<int> ip)
{
std::cout << *ip << std::endl;
}
// main线程
int main()
{
std::unique_ptr<int> ip;
std::thread t(print, ip);
return 0;
}
#include
#include
void print(std::unique_ptr<int> ip)
{
std::cout << ip.get() << std::endl;
}
// main线程
int main()
{
std::unique_ptr<int> ip;
std::thread t1(print, std::move(ip)); // 使用std::move
std::thread t2(print, std::unique_ptr<int>()); // 使用临时变量
t1.join();
t2.join();
return 0;
}
void f(double a);
void test()
{
int i = 0;
std::thread t(f,i);
}
void f(std::string s);
void test()
{
char buffer[1024];
std::thread t(f, buffer);
}
void f(std::string s)
{
std::cout << s << std::endl;
}
void test()
{
char buffer[1024];
std::thread t(f, std::string(buffer)); // 手动显式转换
}
#include
#include
void print()
{
std::cout << 1;
}
// main线程
int main()
{
std::thread t1(print),t2(print);
t1 = std::move(t2); // 错误,向已关联线程实例显式移交线程归属权
t1 = std::thread(print); // 错误,隐式移动
return 0;
}
std::thread getThread()
{
std::thread t;
return t;
}
#include
#include
void setThread(std::thread t)
{
if(t.joinable())t.join(); // 汇合和分离前都必须检查joinable()
}
// main线程
int main()
{
std::thread t1;
setThread(std::move(t1)); // 显式移动
setThread(std::thread()); // 隐式移动
return 0;
}
class scoped_thread
{
std::thread t;
public:
explicit scoped_thread(std::thread t_) :
t(std::move(t_))
{
if (!t.joinable())
throw std::logic_error("No thread");
}
~scoped_thread()
{
t.join();
}
scoped_thread(scoped_thread const&) = delete;
scoped_thread& operator=(scoped_thread const&) = delete;
};
#include
#include
#include // 使用vector容器
#include // 使用windows上的高性能计数器来计时
// 构建一个高性能计时器
class Time
{
public:
double mSecondsPerCount; // 存储每个CPU计数所用秒数
__int64 startTime; // 存储开始计时时CPU已经运行计数
Time() // 在构造函数中获得用户每个CPU计数所用秒数
{
__int64 countsPerSec;
QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); // 获取性能计时器的频率
mSecondsPerCount = 1.0 / (double)countsPerSec; // 计算每个计数包含的秒数
}
void start() // 开始计数,将startTime更新为此时CPU已经过计数
{
QueryPerformanceCounter((LARGE_INTEGER*)&startTime);
}
double getTime() // 获取从开始计数到此时所经过的时间秒数
{
__int64 nowPerSec;
QueryPerformanceCounter((LARGE_INTEGER*)&nowPerSec); // 获取此时CPU计数
// 经过时间 = (现在的计数-开始时计数) * 每计数包含秒数
return (nowPerSec - startTime) * mSecondsPerCount;
}
};
// 测试性能程序,使整形变量自增c次
void test(int c)
{
for (int i = 0; i < c; ++i);
}
// main线程
int main()
{
// 定义计时器、每个线程所要测试的规模数、存储关联线程对象的容器vector
Time time;
int c = 100000000;
std::vector<std::thread> threads;
// 开始计时
time.start();
// 在容器中创建10个线程,每个线程执行c规模的测试程序
for (int i = 0; i < 10; ++i)
{
threads.emplace_back(test, c);
}
// 等待所有子线程结束
for (int i = 0; i < 10; i++)
{
threads[i].join();
}
// 打印多线程执行共10c规模的测试程序所需时间
std::cout << time.getTime() << std::endl;
// 重载计时器,开始计时
time.start();
// 令main线程独立执行10c规模
test(10 * c);
// 打印main线程单独执行10规模的测试程序所需时间
std::cout << time.getTime() << std::endl;
return 0;
}
#include
#include
// main线程
int main()
{
std::cout << std::this_thread::get_id() << std::endl;
std::thread t;
std::cout << t.get_id();
return 0;
}
std::thread::id类型支持复制操作和比较运算,当两个std::thread::id类型的对象相等时,则它们代表相同的线程,或者它们的值都表示线程不存在。如果不相等,则它们代表不同的线程,或者一者表示线程而另一者表示线程不存在。
由于std::thread::id具备全套完整的比较运算符,因此它可以作为关联容器的键值,或者用于排序等其他比较用途。
因此std::thread::id可以用作新标准的无序关联容器的键值。
我们可以在数据结构中存储std::thread::id类型成员,以此保存当前线程的ID,并且将其作为操作的要素以控制权限。比如设置状态-线程ID结构体,调用对象中检查此结构体中的状态,从而判断应当执行哪些操作,并实现检查操作是否合法等功能。
在某些情况下,我们需要将一些数据与线程相关联,但使用如 “将数据存储在线程的局部数据” 等方式却并不合适,这时就可以采用关联容器,以线程ID作为键值,存储每个线程相关联的数据。主线程还可利用此种方式存储每个受控制线程的相关信息,或存储信息以便在线程间相互传递。
绝大多数情况下,不需要额外定义线程ID,除非是把ID作为数组索引等方式使用。