在 C++ 中,线程是用来实现并发编程的重要工具,它允许程序同时执行多个任务。C++11 标准引入了多线程支持,主要通过 <thread>
标头文件提供相关功能,包括线程创建、管理和同步等。
1. 基本概念
- 线程是程序执行的基本单位,一个程序可以包含多个线程。
- 多线程可以提高程序效率,特别是在多核 CPU 上,每个线程可以在不同的核上运行。
- C++ 提供的多线程功能包括:
- 线程的创建与管理(
std::thread
)。
- 同步机制(如互斥锁
std::mutex
、条件变量 std::condition_variable
等)。
- 数据保护(如线程安全的操作)。
2. 创建和管理线程
1) 创建线程
线程可以通过 std::thread
创建,并且可以使用函数、lambda 表达式或可调用对象作为线程入口。
(a) 使用普通函数
1 2 3 4 5 6 7 8 9 10 11 12
| #include <iostream> #include <thread>
void threadFunction() { std::cout << "Thread is running..." << std::endl; }
int main() { std::thread t(threadFunction); t.join(); return 0; }
|
- **
std::thread t(threadFunction)
**:创建线程并执行 threadFunction
。
- **
t.join()
**:主线程等待 t
线程执行完成。
(b) 使用 lambda 表达式
1 2 3 4 5 6 7 8 9 10 11
| #include <iostream> #include <thread>
int main() { std::thread t([] { std::cout << "Thread running with lambda!" << std::endl; });
t.join(); return 0; }
|
(c) 使用类的成员函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <thread>
class Worker { public: void operator()() { std::cout << "Thread running with functor!" << std::endl; } };
int main() { Worker worker; std::thread t(worker); t.join(); return 0; }
|
2) 分离线程(detach
)
分离线程允许主线程与新线程独立运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream> #include <thread> #include <chrono>
void threadFunction() { std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "Detached thread completed!" << std::endl; }
int main() { std::thread t(threadFunction); t.detach(); std::cout << "Main thread continues..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(3)); return 0; }
|
注意:分离的线程在程序结束前需要完成,否则会出现未定义行为。
3) 获取线程 ID
1 2
| std::thread::id id = std::this_thread::get_id(); std::cout << "Thread ID: " << id << std::endl;
|
3. 线程同步
由于线程是并发执行的,因此多个线程访问共享资源时可能会导致数据竞争(Race Condition)。C++ 提供了多种同步工具来避免这种问题。
1) 互斥锁(std::mutex
)
互斥锁用于保证只有一个线程可以访问共享资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <iostream> #include <thread> #include <mutex>
std::mutex mtx;
void printMessage(const std::string& message) { std::lock_guard<std::mutex> lock(mtx); std::cout << message << std::endl; }
int main() { std::thread t1(printMessage, "Thread 1: Hello"); std::thread t2(printMessage, "Thread 2: World");
t1.join(); t2.join(); return 0; }
|
- **
std::lock_guard
**:管理锁的生命周期,防止忘记解锁。
- **
mtx.lock()
和 mtx.unlock()
**:手动加锁和解锁,但可能导致死锁,不推荐使用。
2) 条件变量(std::condition_variable
)
条件变量用于实现线程间的协调,例如一个线程等待某个条件成立时再执行。
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 26 27 28 29 30 31
| #include <iostream> #include <thread> #include <condition_variable> #include <mutex>
std::mutex mtx; std::condition_variable cv; bool ready = false;
void worker() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, [] { return ready; }); std::cout << "Worker thread is running!" << std::endl; }
void notify() { { std::lock_guard<std::mutex> lock(mtx); ready = true; } cv.notify_one(); }
int main() { std::thread t1(worker); std::thread t2(notify);
t1.join(); t2.join(); return 0; }
|
3) 原子操作(std::atomic
)
原子操作用于多线程中对单个变量的操作,避免数据竞争。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> #include <thread> #include <atomic>
std::atomic<int> counter(0);
void increment() { for (int i = 0; i < 1000; ++i) { ++counter; } }
int main() { std::thread t1(increment); std::thread t2(increment);
t1.join(); t2.join();
std::cout << "Final counter: " << counter << std::endl; return 0; }
|
4. 注意事项
- 数据竞争:多个线程同时修改共享资源可能导致错误,需要使用同步机制。
- 死锁:多个线程互相等待资源,导致程序无法继续。
- 分离线程的风险:主线程结束时,分离的线程未完成可能会导致崩溃。
- 性能开销:线程切换会带来一定的系统开销。
5. 总结
- 线程创建:
std::thread
提供简单易用的接口。
- 线程同步:使用
std::mutex
、std::condition_variable
等工具保护共享数据。
- 线程安全:推荐使用
std::atomic
或其他同步机制避免数据竞争。
线程是 C++ 中实现并发的核心工具,但需要小心处理共享资源和线程生命周期,确保程序的正确性和性能。