Thread库
- 创建线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream> #include <thread> #include <string>
void printHelloworld(std::string msg) { std::cout << msg << std::endl; return; } int main() { std::thread thread1(printHelloworld, "Hello Thread"); thread1.join(); thread1.detach(); bool isJoin = thread1.joinable(); if (isJoin) { thread1.join(); } return 0; }
|
- join()是阻塞的
img
本文详细介绍C++11
Thead线程库的基本使用,包括如何创建线程、启动线程、等待线程完成以及如何分离线程等。
创建线程
要创建线程,我们需要一个可调用的函数或函数对象,作为线程的入口点。在C++11中,我们可以使用函数指针、函数对象或lambda表达式来实现。创建线程的基本语法如下:
#include std::thread t(function_name, args...);
function_name是线程入口点的函数或可调用对象
args...是传递给函数的参数
创建线程后,我们可以使用t.join()等待线程完成,或者使用t.detach()分离线程,让它在后台运行。
例如,下面的代码创建了一个线程,输出一条消息:
1 2 3 4 5 6 7 8 9 10 11 12
| #include <iostream> #include <thread> void print_message() { std::cout << "Hello, world!" << std::endl; } int main() { std::thread t(print_message); t.join(); return 0; }
|
在这个例子中,我们定义了一个名为print_message的函数,它输出一条消息。然后,我们创建了一个名为t的线程,将print_message函数作为入口点。最后,我们使用t.join()等待线程完成。
传递参数
我们可以使用多种方式向线程传递参数,例如使用函数参数、全局变量、引用等。如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> #include <thread> void print_message(const std::string& message) { std::cout << message << std::endl; } void increment(int& x) { ++x; } int main() { std::string message = "Hello, world!"; std::thread t(print_message, message); t.join(); int x = 0; std::thread t2(increment, std::ref(x)); t2.join(); std::cout << x << std::endl; return 0; }
|
在第一个例子中,我们使用了一个字符串作为函数参数,传递给线程。在第二个例子中,我们使用了一个引用来传递一个整数变量。需要注意的是,当我们使用引用传递参数时,我们需要使用std::ref来包装引用,否则编译器会报错。
等待线程完成
当我们创建一个线程后,我们可能需要等待它完成,以便获取线程的执行结果或执行清理操作。我们可以使用t.join()方法来等待线程完成。例如,下面的代码创建了两个线程,等待它们完成后输出一条消息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <iostream> #include <thread> void print_message(const std::string& message) { std::cout << message << std::endl; } int main() { std::thread t1(print_message, "Thread 1"); std::thread t2(print_message, "Thread 2"); t1.join(); t2.join(); std::cout << "All threads joined" << std::endl; return 0; }
|
在这个例子中,我们创建了两个线程t1和t2,它们都调用print_message函数输出一条消息。然后,我们使用t1.join()和t2.join()等待它们完成。最后,我们输出一条消息,表示所有线程都已经完成。
分离线程
有时候我们可能不需要等待线程完成,而是希望它在后台运行。这时候我们可以使用t.detach()方法来分离线程。例如,下面的代码创建了一个线程,分离它后输出一条消息:
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream> #include <thread> void print_message(const std::string& message) { std::cout << message << std::endl; } int main() { std::thread t(print_message, "Thread 1"); t.detach(); std::cout << "Thread detached" << std::endl; return 0; }
|
在这个例子中,我们创建了一个名为t的线程,调用print_message函数输出一条消息。然后,我们使用t.detach()方法分离线程,让它在后台运行。最后,我们输出一条消息,表示线程已经被分离。
需要注意的是,一旦线程被分离,就不能再使用t.join()方法等待它完成。而且,我们需要确保线程不会在主线程结束前退出,否则可能会导致未定义行为。
joinable()
joinable()方法返回一个布尔值,如果线程可以被join()或detach(),则返回true,否则返回false。如果我们试图对一个不可加入的线程调用join()或detach(),则会抛出一个std::system_error异常。
下面是一个使用joinable()方法的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13
| #include <iostream> #include <thread> void foo() { std::cout << "Thread started" << std::endl; } int main() { std::thread t(foo); if (t.joinable()) { t.join(); } std::cout << "Thread joined" << std::endl; return 0; }
|
常见错误(将在后续文章中详解以下错误的解决方案)
在使用C++11线程库时,有一些常见的错误需要注意。例如:
-
忘记等待线程完成或分离线程:如果我们创建了一个线程,但没有等待它完成或分离它,那么在主线程结束时,可能会导致未定义行为。
-
访问共享数据时没有同步:如果我们在多个线程中访问共享数据,但没有使用同步机制,那么可能会导致数据竞争、死锁等问题。
-
异常传递问题:如果在线程中发生了异常,但没有处理它,那么可能会导致程序崩溃。因此,我们应该在线程中使用try-catch块来捕获异常,并在适当的地方处理它。
总结
C++11提供了一个强大的线程库,即std::thread。它可以在C++程序中创建和管理线程,提供了一种更加现代化的方式来处理多线程编程。在本文中,我们介绍了std::thread库的基本使用,包括如何创建、启动和管理线程,以及如何等待线程完成和分离线程。同时,我们也提到了一些常见的错误,需要注意避免。