博客
关于我
C++特性之多线程详解
阅读量:802 次
发布时间:2023-04-04

本文共 3968 字,大约阅读时间需要 13 分钟。

1. 多线程与多进程

在C++11之前,若要实现多线程编程,通常需要依赖操作系统提供的API,如Linux的<pthread.h>或Windows的<windows.h>。然而,这些方法存在平台依赖性,编写起来较为复杂。而C++11引入了语言层面的多线程支持,统一了不同平台的实现,极大地简化了多线程开发。

1.1 多进程与多线程的对比

多进程与多线程在并发编程中各有优劣:

  • 多进程并发

    • 优点:操作系统提供的保护机制使得进程间的数据共享较为安全。
    • 缺点
      • 进程间通信复杂且速度较慢。
      • 运行多个进程需要消耗大量资源。
  • 多线程并发

    • 优点:线程是轻量级的进程,共享同一进程的地址空间,数据传递效率高。
    • 缺点:由于缺乏操作系统的保护机制,需程序员手动管理共享数据,避免死锁。

1.2 多线程的理解

多线程的本质是同一进程内多个线程并发执行。然而,单个CPU内核无法真正并行执行多个线程,只能轮流使用时间片。

  • 单CPU内核:多线程并发实际为轮流执行,无法实现真正的并行计算。
  • 多核CPU:多线程可以实现真正的并行计算,充分发挥多核资源。

1.3 创建线程

创建线程的方式有多种:

  • 函数形式

    std::thread myThread(thread_fun);
    std::thread myThread(thread_fun, 100);

    或直接创建并立即运行:

    std::thread (thread_fun, 1).detach();
  • 代码示例

    #include 
    using namespace std;
    void thread_1() {
    cout << "子线程1";
    }
    int main() {
    thread t1(thread_1);
    t1.join();
    return 0;
    }
  • 1.4 join与detach方式

    线程的等待方式有两种:

    • join:主线程等待子线程完成后才能继续。
      myThread.join();
    • detach:子线程独立运行,主线程立即返回。
      myThread.detach();

    可以通过joinable()判断线程是否可等待:

    if (myThread.joinable()) {
    myThread.join();
    }

    2. 互斥量(Mutex)

    互斥量用于保护共享资源,防止竞态条件和死锁。

    2.1 Mutex类型

    C++提供了几种互斥量类型:

    • std::mutex:基本的互斥量。
    • std::recursive_mutex:支持递归使用的互斥量。
    • std::time_mutex:适用于保护在特定时间内的资源。
    • std::recursive_timed_mutex:结合了定时和递归特性。

    2.2 Lock与Unlock

    互斥量的基本操作:

    • lock():上锁资源。
    • unlock():解锁资源。

    2.3 Lock_guard

    Lock_guard是一种简便的互斥量管理方式,自动加锁和解锁:

    std::lock_guard
    lock(g_i_mutex);
    ++g_i;

    2.4 Unique_lock

    Unique_lock提供更高级别的功能,可灵活控制锁定状态:

    std::unique_lock
    lock(mtx, std::defer_lock);

    3. 条件变量(Condition Variable)

    条件变量用于线程间的等待与通知,常用于生产者-消费者模式。

    3.1 Condition Variable的方法

    • wait():阻塞直到被通知。
    • wait_for():阻塞至超时或被通知。
    • wait_until():阻塞至特定时间或被通知。

    3.2 使用示例

    #include 
    #include
    #include
    std::condition_variable cv;
    std::mutex mtx;
    int cargo = 0;
    void consume(int n) {
    std::unique_lock
    lck(mtx);
    cv.wait(lck, [this] { return cargo != 0; });
    std::cout << cargo << '\n';
    cargo = 0;
    }
    int main() {
    std::thread consumer_thread(consume, 10);
    for (int i = 0; i < 10; ++i) {
    std::unique_lock
    lck(mtx);
    cargo = i + 1;
    cv.notify_one();
    }
    consumer_thread.join();
    return 0;
    }

    4. 线程池(ThreadPool)

    线程池通过维护多个工作线程,避免频繁创建与销毁线程的开销,提升性能。

    4.1 线程池的实现

    线程池通常包含以下组件:

    • 工作线程:执行任务。
    • 任务队列:存储待处理任务。
    • 条件变量:同步工作线程与任务队列。
    • 互斥锁:保护共享资源。

    4.2 线程池的优点

    • 减少上下文切换:线程池中的工作线程可以直接处理任务。
    • 提高资源利用率:避免线程闲置等待任务。
    • 简化管理:通过池化方式减少线程创建与销毁的开销。

    4.3 线程池的实现代码

    #include 
    #include
    #include
    #include
    #include
    #include
    namespace threadPool { class ThreadPool { public: ThreadPool(int number = 1) { if (number <= 0 || number > MAX_THREADS) throw std::exception(); for (int i = 0; i < number; ++i) { work_threads.emplace_back(worker, this); } } ~ThreadPool() { stop = true; condition.notify_all(); for (auto& thread : work_threads) thread.join(); } bool append(Task* request) { { std::unique_lock
    lock(queue_mutex); tasks_queue.push(request); } condition.notify_one(); return true; } private: static void* worker(void* arg) { ThreadPool* pool = (ThreadPool*)arg; pool->run(); } void run() { while (!stop) { std::unique_lock
    lck(queue_mutex); if (tasks_queue.empty()) { condition.wait(lck, [this] { return !tasks_queue.empty(); }); continue; } Task* request = tasks_queue.front(); tasks_queue.pop(); request->process(); } } std::vector
    work_threads; std::mutex queue_mutex; std::condition_variable condition; bool stop; }; }

    4.4 线程池的使用

    #include "mythread.h"
    #include
    #include
    using namespace std;
    class Task {
    public:
    void process() {
    long i = 1000000;
    while (i != 0) {
    int j = sqrt(i);
    i--;
    }
    }
    };
    int main() {
    ThreadPool
    pool(6);
    while (true) {
    Task* task = new Task();
    pool.append(task);
    cout << "添加的任务数量: " << pool.tasks_queue.size() << endl;
    sleep(1);
    }
    return 0;
    }

    总结

    C++11引入了对多线程和并发编程的全面支持,通过标准化的接口和机制,简化了开发流程。理解多线程与多进程的区别,掌握互斥量与条件变量的使用,以及线程池的实现,对于高效的并发编程至关重要。

    转载地址:http://yirfk.baihongyu.com/

    你可能感兴趣的文章
    MyPython
    查看>>
    MTD技术介绍
    查看>>
    MySQL
    查看>>
    MySQL
    查看>>
    mysql
    查看>>
    MTK Android 如何获取系统权限
    查看>>
    MySQL - 4种基本索引、聚簇索引和非聚索引、索引失效情况、SQL 优化
    查看>>
    MySQL - ERROR 1406
    查看>>
    mysql - 视图
    查看>>
    MySQL - 解读MySQL事务与锁机制
    查看>>
    MTTR、MTBF、MTTF的大白话理解
    查看>>
    mt_rand
    查看>>
    mysql /*! 50100 ... */ 条件编译
    查看>>
    mudbox卸载/完美解决安装失败/如何彻底卸载清除干净mudbox各种残留注册表和文件的方法...
    查看>>
    mysql 1264_关于mysql 出现 1264 Out of range value for column 错误的解决办法
    查看>>
    mysql 1593_Linux高可用(HA)之MySQL主从复制中出现1593错误码的低级错误
    查看>>
    mysql 5.6 修改端口_mysql5.6.24怎么修改端口号
    查看>>
    MySQL 8.0 恢复孤立文件每表ibd文件
    查看>>
    MySQL 8.0开始Group by不再排序
    查看>>
    mysql ansi nulls_SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON 什么意思
    查看>>