線程管理
1. 啟動線程
啟動一個簡單的線程範例 1
使用普通函數#include <thread>
#include <iostream>
void do_task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
int main()
{
//創建一個線程
std::thread t = std::thread(do_task);
//堵塞主線程,等待子線程執行完畢
t.join();
std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;
return 0;
}
範例 2
使用lambda#include <thread>
#include <iostream>
int main()
{
for (int i = 0; i < 20; ++i) {
std::thread t = std::thread([i](){
std::cout << "thread " << i << " id:" << std::this_thread::get_id() << std::endl;
});
t.join();
}
std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;
return 0;
}
範例 3
仿函數(重載運算符)#include <thread>
#include <iostream>
class Task
{
public:
//重載()操作符
void operator()(int i)
{
std::cout << "task thread " << i << "id:" << std::this_thread::get_id() << std::endl;
}
};
int main()
{
Task task;
//創建線程,並且傳遞參數
std::thread t = std::thread(task, 10);
//堵塞主線程,等待子線程完成
t.join();
std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;
return 0;
}
2.向線程傳遞參數
默認的方式是使用拷貝的方式,複製到線程空間,即使參數的類型是引用使用指針傳遞參數
#include <thread>
#include <stdio.h>
void task(const char* pBuffer, int n)
{
fprintf(stdout, "buffer: %s, %d", pBuffer, n);
}
int main()
{
char* buffer = NULL;
int n = 10;
//申請12字節的內存
buffer = (char*)malloc(sizeof(char) * 12);
//拷貝到數據到buffer
strcpy(buffer, "hello thread");
//傳遞的參數, 不能是右值的零時變量
std::thread t = std::thread(task, buffer, n);
t.join();
return 0;
}
使用std::ref
#include <thread>
#include <iostream>
#include <string>
class ObjectClass
{
public:
ObjectClass(std::string& data)
:m_data(data)
{}
public:
std::string& m_data;
};
void func(ObjectClass& object)
{
std::cout << "objectName:" << object.m_data << std::endl;
}
int main()
{
std::string tag = "object";
ObjectClass object(tag);
//創建線程, 使用std::ref傳遞引用的對象
std::thread t = std::thread(func, std::ref(object));
//堵塞線程,等待子線程執行完畢
t.join();
return 0;
}
使用類中的方法
#include <thread>
#include <iostream>
#include <string>
class ObjectClass
{
public:
explicit ObjectClass(std::string& tag)
:m_tag(tag)
{}
void func(int n)
{
std::cout << "tag:" << this->m_tag << ", n:" << n << std::endl;
}
private:
std::string& m_tag;
};
int main()
{
std::string tag = "object";
ObjectClass object(tag);
//使用類方法,放到子線程中使用;
std::thread t = std::thread(&ObjectClass::func, &object, 10);
//堵塞線程,等待子線程執行完畢
t.join();
return 0;
}
3.線程權限轉移
thread 是可移動(movable), 但是不可複製的(copyable)#include <thread>
#include <iostream>
void do_task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
int main()
{
//創建一個線程
std::thread t = std::thread(do_task);
//線程t的權限移動到t2後,t變得不確定,
std::thread t2 = std::thread(std::move(t));
t2.join();
std::cout << "main thread id:" << std::this_thread::get_id() << std::endl;
return 0;
}
4.異常的線程處理
局部變量
局部變量引用的誤區#include <thread>
#include <iostream>
void task(int* pInt)
{
std::cout << "int value:" << *pInt << std::endl;
}
int main()
{
int i = 10;
//創建線程
std::thread t = std::thread(task, &i);
//分離子線程
t.detach();
//主線程執行完畢,i變量資源回收,i的值變的不確定
return 0;
}
主線程異常
當主線程發生異常時,如何保證子線程正確被回收範例1
子線程不分離#include <thread>
#include <iostream>
#include <exception>
void task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
void do_something()
{
throw std::runtime_error("has exception");
}
int main()
{
std::thread t(task);
try {
//主線程在執行過程中,發生異常,為了正確處理,線程等待,需要加入異常處理
do_something();
} catch (std::exception & e)
{
//等待子線程完成
t.join();
throw e;
}
//等待子線程完成
t.join();
return 0;
}
範例 2
子線程分離#include <thread>
#include <iostream>
#include <exception>
void task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
void do_something()
{
throw std::runtime_error("has exception");
}
int main()
{
//創建線程
std::thread t = std::thread(task);
//線程分離,為了防止在創建線程後發生異常,導致線程無法回收
t.detach();
do_something();
return 0;
}
範例 3
使用資源管理類#include <thread>
#include <iostream>
#include <exception>
class ThreadGuard
{
public:
//構造函數
explicit ThreadGuard(std::thread&t)
:t(t){}
//析構函數
~ThreadGuard()
{
//析構函數時,順道堵塞主線程,等待子線程執行完畢,這就是資源回收
if(t.joinable())
{
t.join();
}
}
private:
std::thread &t;
};
void task()
{
std::cout << "task thread id:" << std::this_thread::get_id() << std::endl;
}
void func()
{
std::thread t = std::thread(task);
ThreadGuard guard(t);
//超出作用域後,自動回收資源
}
void do_task()
{
throw std::runtime_error("exception");
}
int main()
{
func();
do_task();
return 0;
}
閱讀更多 編程教學 的文章