在C++中,线程是并发执行的最小单位。主线程(main thread)通常是一个程序开始执行时系统自动创建的线程,而子线程(child thread或worker thread)则是由主线程或其他子线程创建的线程。
并发执行,又称并发处理,是指计算机同时处理多个任务的能力。这里的“同时”可能是字面意义上的同时(如在多核或多处理器的系统中),也可能是看似同时,实则在一颗单核CPU上,通过快速切换上下文使得任务看起来是在同时执行。
在操作系统中,通过线程和进程的调度实现并发执行。线程或进程会被操作系统分配CPU时间片,然后在每个时间片上执行。当时间片结束时,当前线程或进程会被暂停,另一个线程或进程会被唤醒继续执行。这样通过快速切换,可以让用户感觉到所有线程或进程都在同时运行,这就是并发执行。
并发执行的主要优点是能够提高系统的响应性和吞吐量。例如,一个Web服务器就需要并发处理大量的用户请求。在一些高性能计算的应用中,比如图像处理、科学计算等,也需要并发执行来提高计算效率。然而,编写和调试并发程序相比单线程程序来说会更复杂,主要原因是需要处理线程或进程间的同步和通信问题,比如数据的竞态条件、死锁等。
主线程:这是由操作系统创建并启动的线程,它通常负责执行程序的主要任务。它也是程序的入口点,当你的程序开始运行时,它就会开始执行。
所谓的"主线程"
main
,其入口代码是类似这样的方式调用main
的:exit(main(...))
。
main
执行完之后, 会调用exit()
。
exit()
会让整个进程over
终止,那所有线程自然都会退出。
子线程:这些线程是在程序运行期间由主线程或其他子线程创建的。子线程可以与主线程并行执行,这对于需要同时处理多个任务的情况非常有用。
当你创建一个子线程时,你需要给定一个函数或方法,该线程将从该函数开始执行。子线程会独立于创建它的线程运行,同时还可以访问共享数据。
然而,子线程的生命周期不受创建它的线程控制。也就是说,即使创建子线程的线程已经终止(比如主线程已经结束),子线程仍然可以继续运行,除非整个进程都被终止。在C++中,如果主线程在子线程之前结束并调用了exit(),那么整个进程(包括所有的子线程)都会被终止。
例如,以下是一个创建并等待子线程完成的例子:
#include <iostream>
#include <thread>// 子线程要运行的函数
void child_function() {for (int i = 0; i < 5; ++i) {std::cout << "Child thread: " << i << std::endl;}
}int main() {// 创建并启动子线程std::thread child_thread(child_function);// 在主线程中做一些事情for (int i = 0; i < 5; ++i) {std::cout << "Main thread: " << i << std::endl;}// 等待子线程完成child_thread.join();return 0;
}
在这个例子中,主线程创建并启动了一个子线程,并等待子线程完成执行。主线程和子线程并发执行,并且都可以访问std::cout进行输出。然而,如果没有正确的同步机制,多个线程同时写入同一资源可能会导致数据竞争。
这里有一个C++中使用线程的例子:
#include <iostream>
#include <thread>void function_1() {std::cout << "Function 1 is called from a child thread" << std::endl;
}int main() {std::cout << "Main thread starts" << std::endl;// 创建一个子线程,执行function_1std::thread thread_1(function_1);// 等待子线程结束thread_1.join();std::cout << "Main thread ends" << std::endl;return 0;
}
在这个例子中,主线程开始执行,然后创建一个子线程来执行function_1。主线程会等待子线程执行完毕,然后继续执行,最后结束。每个线程都独立执行,具有自己的指令指针和一组寄存器等。
这是一个基础的线程使用例子,实际应用中可能会涉及到更多的问题,比如线程之间的同步、互斥,线程的调度等。所以在使用多线程时,我们需要更深入地了解和熟悉线程的特性和相关的问题。