1.创建线程
2.守护线程
3.可调用对象
4.传参
5.线程的移动和复制
6.线程id
7.互斥mutex
总结
1.创建线程直接初始话thread
类对象进行创建线程,创建线程后调用join()
方法,让主线程等待子线程完成工程。
#include <iostream>
#include <thread>
void thread_function()
{
std::cout << "thread function\n";
}
int main()
{
std::thread t(&thread_function); // t starts running
std::cout << "main thread\n";
t.join(); // main thread waits for the thread t to finish
return 0;
}
2.守护线程
我们可以调用detach()
方法,将线程变为守护线程,完成线程和主线程的分离。一旦线程分离,我们不能强迫它再次加入主线程,再次调用join()
方法会报错的。
一旦分离,线程应该永远以这种方式存在。调用join()
函数之前可以使用函数joinable()
检查线程是否可以加入主线程,加强程序健壮性。
// t2.cpp
int main()
{
std::thread t(&thread_function);
std::cout << "main thread\n";
if( t.joinable( ) )
// t.join();
// t.join();
t.detach();
return 0;
}
3. 可调用对象
线程可以调用
函数指针
类对象
lamda表达式
1.函数指针
就像之前举例的样子
2.类对象
#include <iostream>
#include <thread>
class MyFunctor
{
public:
void operator()() {
std::cout << "functor\n";
}
};
int main()
{
MyFunctor fnctor;
// 这样是不能运行的,
// std::thread t(fnctor);
// 必须按照这样进行初始话。
// MyFunctor fnctor; Note that we had to add () to enclose the MyFunctor().
std::thread t((MyFunctor())); // it's related to the function declaration convention in C++.
std::cout << "main thread\n";
t.join();
return 0;
}
3.lamda表达式
#include <iostream>
#include <thread>
class MyFunctor
{
public:
void operator()() {
std::cout << "functor\n";
}
};
int main()
{
MyFunctor fnctor;
// 这样是不能运行的,
// std::thread t(fnctor);
// 必须按照这样进行初始话。
// MyFunctor fnctor; Note that we had to add () to enclose the MyFunctor().
std::thread t((MyFunctor())); // it's related to the function declaration convention in C++.
std::cout << "main thread\n";
t.join();
return 0;
}
4. 传参
传参分为三种
1.值传递
2.引用传递
3.不复制,也不共享内存的传参方式move()
#include <iostream>
#include <thread>
#include <string>
void thread_function(std::string s)
{
std::cout << "thread function ";
std::cout << "message is = " << s << std::endl;
}
int main()
{
std::string s = "Kathy Perry";
// 1. 值传递
std::thread t(&thread_function, s);
// 2. 引用传递
std::thread t(&thread_function, std::ref(s));
// 3. 不复制,也不共享内存的传参方式`move()
std::thread t(&thread_function, std::move(s));
std::cout << "main thread message = " << s << std::endl;
t.join();
return 0;
}
5. 线程的移动和复制
// t5.cpp
#include <iostream>
#include <thread>
void thread_function()
{
std::cout << "thread function\n";
}
int main()
{
std::thread t(&thread_function);
std::cout << "main thread\n";
// transfer the ownership of the thread by moving it:
std::thread t2 = move(t);
t2.join();
return 0;
}
6.线程id
获取线程的id: this_thread::get_id()
总共有多少个线程:std::thread::hardware_concurrency()
程序
int main()
{
std::string s = "Kathy Perry";
std::thread t(&thread_function, std::move(s));
std::cout << "main thread message = " << s << std::endl;
std::cout << "main thread id = " << std::this_thread::get_id() << std::endl;
std::cout << "child thread id = " << t.get_id() << std::endl;
t.join();
return 0;
}
输出
7. 互斥mutexthread function message is = Kathy Perry
main thread message =
main thread id = 1208
child thread id = 5224
互斥锁可能是 C++ 中使用最广泛的数据保护机制,但重要的是构造我们的代码以保护正确的数据并避免接口中固有的竞争条件。互斥锁也有自己的问题,表现为死锁和保护太多或太少的数据
标准 C++ 库提供了std::lock_guard
类模板,它实现 了互斥锁的RAII
习惯用法。它在构造时锁定提供的互斥锁并在销毁时解锁它,从而确保始终正确解锁锁定的互斥锁。
#include <iostream>
#include <thread>
#include <list>
#include <algorithm>
#include <mutex>
using namespace std;
// a global variable
std::list<int>myList;
// a global instance of std::mutex to protect global variable
std::mutex myMutex;
void addToList(int max, int interval)
{
// the access to this function is mutually exclusive
std::lock_guard<std::mutex> guard(myMutex);
for (int i = 0; i < max; i++) {
if( (i % interval) == 0) myList.push_back(i);
}
}
void printList()
{
// the access to this function is mutually exclusive
std::lock_guard<std::mutex> guard(myMutex);
for (auto itr = myList.begin(), end_itr = myList.end(); itr != end_itr; ++itr ) {
cout << *itr << ",";
}
}
int main()
{
int max = 100;
std::thread t1(addToList, max, 1);
std::thread t2(addToList, max, 10);
std::thread t3(printList);
t1.join();
t2.join();
t3.join();
return 0;
}
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注软件开发网的更多内容!