一、std::thread概述
std::thread是C++11提供的多線程庫之一,它提供了一種方便的方式來並行執行代碼,將多個任務同時執行。
std::thread庫提供了創建線程、等待線程結束和管理線程的方法。在std::thread庫中,我們可以使用std::thread對象的構造函數來創建一個新的線程,並告訴它應該執行哪個函數或lambda表達式。當執行完畢時,線程對象可以用join()或detach()方法來終止線程並等待它的結束。
void func1()
{
// ...
}
int main()
{
std::thread t(func1);
// ...
t.join();
return 0;
}
在上面的代碼中,我們定義了一個名為func1()的函數,並使用std::thread對象t在新線程中執行func1()函數。使用join()方法等待線程結束。在主線程中,我們可以執行其他操作,並在最後等待線程結束。
二、std::thread的創建和聲明
std::thread對象的創建方式有多種方法,這裡列舉其中的兩種方法。
第一種,使用函數指針創建線程:
// 一個簡單的函數
void task1(int n)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "task1: " << n << std::endl;
}
int main()
{
std::thread t(task1, 1); // task1函數的參數是1
std::cout << "main thread\n";
t.join();
return 0;
}
第二種,使用lambda表達式創建線程:
int main()
{
std::thread t([](int n) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "task2: " << n << std::endl;
}, 2);
std::cout << "main thread\n";
t.join();
return 0;
}
注意:使用lambda表達式時,需要在參數列表中指定要傳遞給線程的值。
三、std::thread的數據共享和同步
多線程編程時,可能會遇到數據共享和同步的問題。對於數據共享的問題,很容易就會想到使用全局數據或靜態數據。
// 全局變量
int g_count = 0;
void task1()
{
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
++g_count;
}
}
int main()
{
std::thread t1(task1);
std::thread t2(task1);
t1.join();
t2.join();
std::cout << "g_count = " << g_count << std::endl;
return 0;
}
然而,在多個線程中同時訪問全局變量或靜態變量時,可能會出現數據競爭。在上面的示例中,我們想要將g_count變量遞增五次,但在實際執行過程中,可能出現每個線程各自的計數和。
因此,我們需要使用互斥量來同步訪問。
std::mutex g_mutex;
int g_count = 0;
void task2()
{
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::lock_guard<std::mutex> lock(g_mutex);
++g_count;
}
}
int main()
{
std::thread t3(task2);
std::thread t4(task2);
t3.join();
t4.join();
std::cout << "g_count = " << g_count << std::endl;
return 0;
}
在上面的示例中,我們使用了互斥量g_mutex,通過std::lock_guard<std::mutex> lock(g_mutex)來保護對g_count變量的訪問。
四、std::thread的一些其他方法
std::thread還提供了一些其他方法來管理線程。
在主線程中,我們可以通過調用std::this_thread::get_id()來獲取當前線程的id。
std::cout << "main thread id = " << std::this_thread::get_id() << std::endl;
在線程中,我們可以使用std::thread::yield()來暫停當前線程,允許其他線程執行。
void task3()
{
for (int i = 0; i < 5; ++i) {
std::this_thread::yield();
std::cout << "task3\n";
}
}
int main()
{
std::thread t5(task3);
for (int i = 0; i < 5; ++i) {
std::cout << "main\n";
}
t5.join();
return 0;
}
在上面的示例中,我們通過std::thread::yield()方法來將控制權交給其他線程,以便其他線程有機會執行。
std::thread還提供了detach()方法來在後台運行線程。
void task4()
{
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "task4: " << i << std::endl;
}
}
int main()
{
std::thread t6(task4);
t6.detach();
std::cout << "main thread\n";
return 0;
}
在上面的示例中,我們使用detach()方法來後台運行線程t6,並且在主線程中繼續執行其他操作。
五、std::thread的注意事項
在使用std::thread時,需要注意以下幾點:
- 使用std::this_thread::sleep_for()或std::this_thread::sleep_until()代替std::sleep()。
- 不能將std::thread對象的拷貝賦值給其他變量或傳遞給函數。
- std::thread應該在函數結束前被join()或detach()。
- 對於臨界區的訪問,應該使用std::lock_guard<std::mutex>或std::unique_lock<std::mutex>。
六、總結
本文介紹了std::thread庫的一些基本用法,包括聲明和創建線程、線程的數據共享和同步、std::thread的一些其他方法以及注意事項。在多線程編程時,需要特別注意線程安全和數據同步,避免出現數據競爭等問題。
原創文章,作者:RVUP,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/133532.html