std::thread Value&Value.joinable()总是成对出现
他们的关系就像是构造函数和析构函数一样,如果创建一个线程而不去joinable这个线程,很有可能造成MainThread已经结束但是this_thread并没有结束,导致this_thread(workThread)无法正常完成工作或者无法正常退出,引发错误。
joinable的作用是询问当前线程是否已经运行完毕,如果没有运行完毕,MainThread则会在这一行继续等待,这里的等待不是while(true)这样低效的等待,而是将MainThread挂起,释放CPU资源,不会浪费资源,需要注意的是,此时MainThread是挂起状态,代码不会继续向下运行,需要加joinable的地方应该是我们预计这个WorkThread即将完成任务时或者MainThread要结束的时候添加。一是保证MainThread不会在应该运行时挂起,二是保证WorkThread能够正常退出。
与joinable相关的还有个join方法,实际上join方法才是真正的等
使用Lmabda表达式(匿名函数)来为工作线程传入参数
Lmabda表达式是一种匿名函数,很适合某个方法只运行一次或者操作一次时使用,这样我们不必再额外添加一个方法或者在已经封装好的类中添加成员方法,这都不符合封装开放原则。Lmabda表达式就很合适解决这类问题。
Lmabda表达式的结构如下:
//Lmabda Function as same as inline Function
//lambda Function def No name,It is useful to Quickly code a algorithm
//auto RealWorks = [&counter2, &TotalValue_2](auto IterStart, auto IterEnd) {
// for (; IterStart != IterEnd; ++IterStart) {
// TotalValue_2 += Count_Up(*IterStart);
// counter2.Add_Value();
// }
//};
auto localvalue = [函数对象参数](操作符重载函数参数)mutable 或 exception 声明 -> 返回值类型{
函数体};
[函数对象参数]
标识Lmabda表达式的开始,这部分是基础,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义 Lambda 为止时 Lambda 所在作用范围内可见的局部变量(包括 Lambda 所在类的 this)。
也就是说如果要在Lmabda表达式中使用局部变量的时候,需要在[]中将其显式的写出,这样编译器才会去寻找这些局部变量,并将其加载到Lmabda表达式中。
下面给出函数对象参数的形式:
-
[] 不传入任何对象参数
-
[=] 函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)
-
[&] 函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式(相当于是编译器自动为我们按引用传递了所有局部变量)。
-
[this] 函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式(相当于是编译器自动为我们按引用传递了所有局部变量)。
-
[Value] 将 Value 按值进行传递。按值进行传递时,函数体内不能修改传递进来的 a 的拷贝,因为默认情况下函数是 const 的,要修改传递进来的拷贝,可以添加 mutable 修饰符。
-
[&Value] 将 Value 按引用进行传递。
-
[A,&B] 将A按值传递,B按引用进行传递。
-
[=,&A,&B] 除A和B按引用进行传递外,其他参数都按值进行传递。
-
[&,A,B] 除A和B按值进行传递外,其他参数都按引用进行传递。.
(操作符重载函数参数)
标识重载的 () 操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如: (a, b))和按引用 (如: (&a, &b)) 两种方式进行传递。
mutable 或 exception 声明
这部分可以省略。按值传递函数对象参数时,加上 mutable 修饰符后,可以修改传递进来的拷贝(注意是能修改拷贝,而不是值本身)。exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。
-> 返回值类型
标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
{函数体}
标识函数的实现,这部分不能省略,但函数体可以为空。
例子
void ShowIt(int X, int Y, int Z) {
std::cout << X << " " << Y << " " << Z << " " << std::endl;
}
void Plus(int X, int Y, int& Z) {
Z += X + Y; }
void PrintString(const std::string& str1, const std::string& str2