什么是线程?
在计算机科学中,线程是进程中的一个执行控制单元,也被称为执行路径。每个进程可以包含多个线程,每条线程并行执行不同的任务。线程是操作系统可识别的最小执行和调度单位。
进程和线程的区别
- 进程是程序在某个数据集合上的一次运行活动,也是操作系统进行资源分配和保护的基本单位。每个进程都有独立的地址空间、PCB(进程控制块)和资源。进程可以包含一个或多个线程。
- 线程是进程中的一个执行路径,用于保证程序的实时性和实现进程内部的并发。一个进程中至少有一个线程在负责控制程序的执行。如果一个进程有多个执行路径,这个程序就称为多线程程序。
线程发起的例子
让我们通过一个简单的例子来理解线程的概念。假设我们要编写一个C++程序,创建两个线程来同时打印一些消息:
#include <iostream>
#include <thread>
// 线程函数:打印消息
void printMessage(const std::string& message) {
for (int i = 0; i < 5; ++i) {
std::cout << message << " (" << i + 1 << ")" << std::endl;
}
}
int main() {
// 创建两个线程并启动
std::thread thread1(printMessage, "Thread 1");
std::thread thread2(printMessage, "Thread 2");
// 等待两个线程完成
thread1.join();
thread2.join();
std::cout << "Main thread finished." << std::endl;
return 0;
}
在上面的例子中,我们创建了两个线程(thread1
和thread2
),每个线程都调用了printMessage
函数来打印消息。这两个线程并行执行,输出结果可能交错出现。
detach()函数
当我们在C++中创建线程时,有时我们希望线程在后台运行,不阻塞主线程的执行。这就是detach
功能的作用。
detach()
是一个线程对象的成员函数,用于将线程与其创建的执行路径分离。具体来说:
- 当我们调用
detach()
时,线程对象不再与主线程关联。这意味着主线程和子线程之间的生命周期不再相互依赖。 - 分离后的线程将在后台运行,直到其执行完成或被终止。
- 如果主线程结束了,而分离的线程仍在运行,那么分离的线程会继续执行,直到完成。
需要注意以下几点:
- 分离后的线程不能被加入(join)。
- 分离后的线程不应该访问主线程中的局部变量或资源,因为它们可能已经被销毁。
lambda表达式作为函数参数传入线程
Lambda表达式是一种匿名函数,可以作为函数参数传递给其他函数。在C++11中,我们可以使用Lambda表达式来代替函数指针。Lambda表达式的语法格式如下:
[capture list] (parameters) -> return type { body }
其中,capture list
用于捕获外部变量,parameters
用于指定参数列表,return type
用于指定返回值类型,body
用于指定函数体。
例如,下面的代码演示了如何将Lambda表达式作为参数传递给线程:
#include <iostream>
#include <thread>
int main() {
std::thread myThread([](const std::string& str) {
std::cout << "myThread running ..., str is " << str << std::endl;
}, "HelloThread");
myThread.join(); // 分离线程
// 主线程继续执行其他任务
std::cout << "Main thread continues." << std::endl;
// 注意:如果主线程结束了,分离的线程可能还在运行
return 0;
}
move操作
在C++中,move
操作是一种将对象的所有权从一个对象转移到另一个对象的机制,它允许我们避免不必要的拷贝操作,从而提高程序的性能。
在C++11中,标准库提供了一个非常有用的函数 std::move()
,它可以将一个左值强制转换为右值引用。具体来说,std::move()
函数将一个左值强制转换为右值引用,并返回一个指向该右值引用的指针。这个指针可以被传递给其他函数,以实现移动语义。