» C++快速入门 » 2. 高级篇 » 2.4 并发

并发

在 C++ 中,通常使用线程实现并发。线程是进程内独立运行的执行流,它们在同一个进程内独立运行。它们共享相同的内存空间,允许它们相互通信和协调。

线程

<thread> 头文件提供了在 C++ 中使用线程的类和函数。

#include <iostream>
#include <thread>

// 要由线程执行的函数
void printNumbers(int start, int end) {
    for (int i = start; i <= end; ++i) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
}

int main() {
    // 创建两个线程,并传递要由每个线程执行的函数
    std::thread t1(printNumbers, 1, 5);
    std::thread t2(printNumbers, 6, 10);

    // 等待两个线程都完成
    t1.join();
    t2.join();

    return 0;
}

互斥锁 Mutex

互斥锁(Mutex 即 "mutual exclusion")是并发编程中用于确保同一时刻只有一个线程能够访问共享资源或关键代码部分的同步机制。

使用互斥锁的目的是防止多个线程尝试同时修改共享数据时可能发生的数据破坏和意外行为。

#include <iostream>
#include <thread>
#include <mutex>

// 在线程之间共享的全局变量
int sharedData = 0;

// 用于保护对 sharedData 的访问的互斥锁
std::mutex dataMutex;

// 要由线程执行的函数
void incrementSharedData(int iterations) {
    for (int i = 0; i < iterations; ++i) {
        // 在访问 sharedData 之前锁定互斥锁
        std::lock_guard<std::mutex> lock(dataMutex);
        
        // 以线程安全的方式递增 sharedData
        sharedData++;
    }
}

int main() {
    // 创建两个线程,并传递要由每个线程执行的函数
    std::thread t1(incrementSharedData, 1000000);
    std::thread t2(incrementSharedData, 1000000);

    // 等待两个线程都完成
    t1.join();
    t2.join();

    // 输出 sharedData 的最终值
    std::cout << "Final value of sharedData: " << sharedData << std::endl;

    return 0;
}

为确保递增操作是线程安全的,使用 std::lock_guard 在访问 sharedData 之前锁定 dataMutex。这确保一次只有一个线程可以访问共享数据,防止数据竞争。

条件变量

条件变量是一种用于线程间通信的同步原语。它提供了一种方法,使线程能够阻塞直到某个条件为真,从而允许线程协调它们之间的活动。

C++ 标准库提供了 <condition_variable> 头文件来实现条件变量。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool dataReady = false;

// 第一个线程执行的函数
void prepareData() {
    // 模拟一些工作
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // 锁定互斥锁并将条件设置为 true
    {
        std::lock_guard<std::mutex> lock(mtx);
        dataReady = true;
    }

    // 通知等待的线程数据已准备好
    cv.notify_one();
}

// 第二个线程执行的函数
void processData() {
    // 锁定互斥锁(unique_lock 提供更大的灵活性)
    std::unique_lock<std::mutex> lock(mtx);

    // 等待条件为真
    cv.wait(lock, []{ return dataReady; });

    // 处理数据
    std::cout << "Data processing started." << std::endl;

    // 显式解锁互斥锁
    lock.unlock();

    // 继续处理数据
    std::this_thread::sleep_for(std::chrono::milliseconds(200));

    std::cout << "Data processing completed." << std::endl;
}

int main() {
    // 创建两个线程,并传递要由每个线程执行的函数
    std::thread t1(prepareData);
    std::thread t2(processData);

    // 等待两个线程都完成
    t1.join();
    t2.join();

    return 0;
}

代码挑战

编写一个 C++ 程序,模拟两个线程之间共享的简单缓冲区。一个生产者线程(Producer)向缓冲区添加项目,另一个消费者线程(Consumer)从缓冲区中移除项目。 使用 mutex 以确保线程安全。

Loading...
> 此处输出代码运行结果
上页
下页