C++ 并发

17 Mar 2025 | 6 分钟阅读

C++ 是一种强大而通用的编程语言。它支持广泛的编程范式,包括并发。并发是指程序中同时执行多个执行线程的能力。它能提高性能和响应能力,尤其是在涉及 I/O 密集型或 CPU 密集型任务的应用程序中。C++ 提供了内置的并发编程功能和库,例如线程、互斥锁、条件变量和 future。

1. 线程

线程是一系列可以独立于主程序执行的指令。在 C++ 中,可以使用标准库中的 std::thread 类来创建线程。下面通过一个例子来理解这一点。

示例 1

输出

C++ Concurrency

说明

在此示例中,通过将 "hello" 函数作为参数传递给 std::thread 构造函数来创建新线程。然后,在程序退出之前,调用线程对象的 join() 方法等待线程完成。

2. 互斥锁

互斥锁是一种同步对象,可用于保护共享资源免受多个线程的并发访问。在 C++ 中,可以使用标准库中的 std::mutex 类来创建互斥锁。下面通过一个例子来理解这一点。

示例 2

输出

C++ Concurrency

说明

在此示例中,使用 std::mutex 类创建了一个互斥锁。在访问共享资源(在本例中为标准输出流)之前,调用了互斥锁对象的 lock() 方法。然后,在访问完共享资源后,调用 unlock() 方法释放互斥锁。

3. 条件变量

条件变量是一种同步对象,它会阻塞线程,直到满足特定条件。在 C++ 中,可以使用标准库中的 std::condition_variable 类来创建条件变量。下面通过一个例子来理解这一点。

示例 3

输出

C++ Concurrency

说明

在此示例中,使用 std::condition_variable 类创建了一个条件变量。调用条件变量的 wait() 方法以阻塞线程,直到另一个线程通知它。然后,调用 notify_one() 方法通知等待的线程条件已满足。std::unique_lock<std::mutex> 用于自动锁定和解锁互斥锁对象。

4. Future

Future 是一种同步对象,可用于从正在异步执行的线程或函数中检索值。在 C++ 中,可以使用标准库中的 std::future 类来创建 Future。下面通过一个例子来理解这一点。

示例 4

输出

C++ Concurrency

说明

在此示例中,通过 std::future 类创建了一个 Future。调用 std::async() 函数来启动新线程并异步执行 hello 函数。然后,调用 Future 对象的 get() 方法以检索 hello 函数的返回值。

5. 多线程

多线程是指在一个应用程序中执行多个代码线程的能力。线程是独立的执行路径,可以相互并发运行。这对于需要并行处理的应用程序很有用,例如视频编码、科学模拟或图形渲染。在 C++ 中,可以通过标准模板库 (STL) 的 thread 类来实现多线程。

多线程示例

输出

C++ Concurrency

说明

在上面的示例中,使用 std::thread 类创建了两个线程,以并发执行 foo 函数。在程序退出之前,对两个线程都调用了 join() 方法以等待它们完成。

6. 并行性

并行性是指使用多个线程或进程同时执行多个任务的能力。并行性对于需要高吞吐量和效率的应用程序很有用,例如数据处理、科学模拟或机器学习。在 C++ 中,可以使用 Parallel STL 库或 OpenMP 来实现并行性。

并行性示例

输出

C++ Concurrency

说明

在上面的示例中,std::for_each 算法用于使用 std::execution::par 策略以并行方式将 lambda 函数应用于向量的每个元素。lambda 函数仅打印当前线程 ID 并通过将元素值加倍来处理该元素。

7. 同步

同步是指协调多个线程或进程之间对共享资源(如内存或文件)的访问的过程。确保对共享资源的并发访问不会导致竞态条件或其他错误非常重要。在 C++ 中,可以使用互斥锁、条件变量或原子操作来实现同步。

同步示例

输出

C++ Concurrency

说明

在上面的示例中,使用互斥锁来同步对 std::cout 对象的访问,该对象是执行 foo 函数的两个线程之间的共享资源。借助 lock() 和 unlock() 方法,我们可以获取和释放互斥锁。

8. 并发模式

并发模式是并发编程中常用的设计模式,用于解决同步、通信和资源管理等常见问题。在 C++ 中,并发模式的示例包括生产者-消费者模式、读者-写者模式和监视器模式。

并发模式示例

输出

C++ Concurrency

说明

在上面的示例中,使用互斥锁、条件变量和共享队列实现了简单的生产者-消费者模式。`producer` 函数生成五个整数值,并以每 500 毫秒的延迟将它们推送到队列中。每次推送后,它会使用 `notify_one()` 方法通知等待的消费者线程。`consumer` 函数使用条件变量的 `wait()` 方法等待生产者线程的通知。它以每 1000 毫秒的延迟消耗队列中的值。

最佳实践

在使用 C++ 进行并发编程时,遵循最佳实践对于确保应用程序的可靠性和效率至关重要。最佳实践包括避免共享的可变状态,使用线程安全的数据结构,尽量减少对锁和同步的使用,并彻底测试代码。

结论

C++ 提供了广泛的并发编程功能和库,例如线程、互斥锁、条件变量和 Future。这些功能可用于提高涉及 I/O 密集型或 CPU 密集型任务的应用程序的性能和响应能力。正确安全地使用这些功能非常重要,因为并发编程可能很复杂且容易出错。但是,通过仔细的设计和测试,C++ 可以成为强大的并发编程工具。