C++ - 多线程/线程间同步机制/异步处理/线程池

传统的C++(C++11标准之前)中并没有引入线程这个概念,在C++11出来之前,如果想要在C++中实现多线程,需要借助操作系统平台提供的API,比如Linux的<pthread.h>,或者windows下的<windows.h> 。

C++11提供了语言层面上的多线程,包含在头文件中,它解决了跨平台的问题,提供了管理线程、保护共享数据、线程间同步操作、原子操作等类。

一、线程管理(std::thread)

std::thread 是 C++ 标准库中用于创建和管理线程的类。

#include<thread>

1、构造函数
  • thread() noexcept: 默认构造函数,创建一个未关联到任何线程的线程对象;
  • template< class Function, class... Args > explicit thread( Function&& f, Args&&... args );: 接受一个可调用对象 f 和参数列表 args,创建一个新的线程来执行该可调用对象,注意如果传递的参数是指针,需要注意生命周期管理。
2、成员函数
  • joinable():检查线程是否正在运行;
  • join(): 等待线程执行结束,阻塞当前线程直到该线程执行完毕;
  • detach(): 分离线程,允许线程在后台执行,不再与当前线程关联;
  • swap(thread&) noexcept: 交换两个线程对象的状态;
  • native_handle(): 获取底层线程的本机句柄。
3、静态成员函数

hardware_concurrency() noexcept: 返回可以并发执行的线程数量的估计。

4、全局函数
  • std::thread::id std::this_thread::get_id() noexcept: 返回当前线程的 ID;
  • std::thread::id std::thread::get_id() noexcept: 返回当前线程的 ID。
5、特殊成员函数
  • std::thread(const thread&) = delete;: 禁用复制构造函数,线程对象不可复制;
  • std::thread& operator=(const thread&) = delete;: 禁用赋值运算符,线程对象不可赋值;
  • std::thread(std::thread&& x) noexcept;: 移动构造函数,移动另一个线程对象的状态;
  • std::thread& operator=(std::thread&& x) noexcept;: 移动赋值运算符,移动另一个线程对象的状态。
6、示例代码
// 构造函数

#include <iostream>
#include <thread>

// 线程函数,接受一个整数参数并打印
void printNumber(int num) {
    std::cout << "Printing number: " << num << std::endl;
}

int main() {
    // 创建一个线程,并传递参数
    int num = 42;
    std::thread t(printNumber, num);

    // 等待线程执行完毕
    t.join();

    std::cout << "Thread finished execution." << std::endl;

    return 0;
}
// 赋值操作

#include <stdio.h>
#include <stdlib.h>

#include <chrono>    // std::chrono::seconds
#include <iostream>  // std::cout
#include <thread>    // std::thread, std::this_thread::sleep_for

void thread_task(int n) {
    std::this_thread::sleep_for(std::chrono::seconds(n));
    std::cout << "hello thread "
        << std::this_thread::get_id()
        << " paused " << n << " seconds" << std::endl;
}

int main(int argc, const char *argv[])
{
    std::thread threads[5];
    std::cout << "Spawning 5 threads...\n";
    for (int i = 0; i < 5; i++) {
        threads[i] = std::thread(thread_task, i + 1);
    }
    std::cout << "Done spawning threads! Now wait for them to join\n";
    for (auto& t: threads) {
        t.join();
    }
    std::cout << "All threads joined.\n";

    return EXIT_SUCCESS;
}
// 等待进程退出(主线程退出时要等待所有子线程退出,确保线程资源在程序结束时得到正确释放)

if (formatThread.joinable()) {
	abortCreateEncfs();
	formatThread.join();
}
// 单次定时器

class SimpleTimer {
public:
	SimpleTimer() : running(false) {}
	void SetCallback(std::function<void()> callback) {
		this->callback = callback;
	}
	void Start(int intervalMs) {
		if (running) {
			Stop();
		}
		running = true;
		timerThread = std::thread([this, intervalMs]() {
			while (running) {
				auto start = std::chrono::steady_clock::now();
				if (callback) {
					callback();
				}
				std::this_thread::sleep_until(start + std::chrono::milliseconds(intervalMs));
			}
			});
	}
	void Stop() {
		running = false;
		if (timerThread.joinable()) {
			timerThread.join();
		}
	}
	~SimpleTimer() {
		Stop();
	}

private:
	std::thread timerThread;
	std::atomic<bool> running;
	std::function<void()> callback;
};

二、线程延时

std::this_thread::sleep_for(std::chrono::duration);

std::chrono 提供了不同的时间单位:

        std::chrono::seconds: 秒

        std::chrono::milliseconds: 毫秒

        std::chrono::microseconds: 微秒

        std::chrono::nanoseconds: 纳秒

使用示例:

        暂停 500 毫秒:std::this_thread::sleep_for(std::chrono::milliseconds(500));

        暂停 1 微秒:std::this_thread::sleep_for(std::chrono::microseconds(1));

三、线程同步

1、互斥量(std::mutex)

std::mutex 是 C++ 标准库中的一个类,用于实现互斥锁,保护共享资源,防止多个线程同时访问。

#include<mutex>

# 构造函数:

std::mutex() noexcept: 默认构造函数,创建一个未加锁的互斥量对象。

# 成员函数:

  • void lock(): 加锁互斥量,如果互斥量已经被另一个线程锁定,则当前线程将阻塞直到互斥量变为可用;
  • bool try_lock(): 尝试加锁互斥量,如果互斥量当前未被锁定,则锁定并返回 true。如果互斥量已经被锁定,则立即返回 false,而不阻塞;
  • void unlock(): 解锁互斥量,调用线程必须拥有互斥量的锁,否则行为未定义。

# RAII封装类:

  • std::lock_guard 适用于简单的互斥量管理,提供一个基本的 RAII 风格的锁机制,当你只需要在作用域内管理互斥量时,它是最简单且高效的选择;
  • std::unique_lock 提供了更高的灵活性,适用于复杂的线程同步场景,支持显式解锁、延迟锁定、条件变量和锁的转移等功能。使用 unique_lock 可以让你在更复杂的同步中更加灵活地控制锁的生命周期。
  • explicit lock_guard(mutex& m): 构造函数,锁定互斥量 m;
  • ~lock_guard(): 析构函数,自动解锁互斥量;
  • explicit unique_lock(mutex& m): 构造函数,锁定互斥量 m;
  • unique_lock(mutex& m, defer_lock_t t): 构造函数,不锁定互斥量,使用 std::defer_lock 标记;unique_lock(mutex& m, try_to_lock_t t): 构造函数,尝试锁定互斥量,使用 std::try_to_lock 标记;
  • unique_lock(mutex& m, adopt_lock_t t): 构造函数,假设调用线程已经锁定了互斥量,使用 std::adopt_lock 标记。
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void printThreadSafe(const std::string& msg) {
    // 使用 lock_guard 自动管理锁的生命周期
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << msg << std::endl;
}

void tryLockExample() {
    if (mtx.try_lock()) {
        std::cout << "try_lock succeeded" << std::endl;
        mtx.unlock();
    } else {
        std::cout << "try_lock failed" << std::endl;
    }
}

int main() {
    std::thread t1(printThreadSafe, "Thread 1: Hello, world!");
    std::thread t2(printThreadSafe, "Thread 2: Hello, world!");

    t1.join();
    t2.join();

    std::thread t3(tryLockExample);
    t3.join();

    return 0;
}
2、递归互斥量(std::recursive_mutex)

std::recursive_mutex 是 C++ 标准库中的一个类,用于实现递归互斥锁,它允许同一个线程多次锁定同一个互斥量,而不会导致死锁。这在递归函数或复杂的代码路径中需要多次进入同一个临界区时特别有用。

#include<mutex>

# 构造函数

recursive_mutex() noexcept: 默认构造函数,创建一个未加锁的递归互斥量对象。

# 成员函数

  • void lock(): 加锁递归互斥量,如果互斥量已经被当前线程锁定,则增加锁定计数,如果被其他线程锁定,则当前线程将阻塞,直到互斥量变为可用;
  • bool try_lock(): 尝试加锁递归互斥量,如果互斥量当前未被锁定或者已经被当前线程锁定,则锁定并返回 true,增加锁定计数,如果被其他线程锁定,则立即返回 false,而不阻塞;
  • void unlock(): 解锁递归互斥量,如果当前线程持有多个锁,则减少锁定计数,直到计数为零时真正释放互斥量。

# RAII封装类

与互斥量一致。

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

std::recursive_mutex rec_mtx;

void recursiveFunction(int count) {
    if (count <= 0) return;

    // 使用 lock_guard 自动管理锁的生命周期
    std::lock_guard<std::recursive_mutex> lock(rec_mtx);
    std::cout << "Recursive call count: " << count << std::endl;
    
    // 递归调用
    recursiveFunction(count - 1);
}

void tryLockExample() {
    if (rec_mtx.try_lock()) {
        std::cout << "try_lock succeeded" << std::endl;
        rec_mtx.unlock();
    } else {
        std::cout << "try_lock failed" << std::endl;
    }
}

int main() {
    // 创建一个线程并调用递归函数
    std::thread t1(recursiveFunction, 5);
    t1.join();

    // 使用 try_lock 示例
    std::thread t2(tryLockExample);
    t2.join();

    return 0;
}
3、条件变量(std::condition_variable)

std::condition_variable 是 C++ 标准库中的一个类,用于实现线程间的同步和通信,允许一个线程等待特定条件,并被其他线程通知条件满足。

#include<condition_variable>

# 构造函数

  • condition_variable() noexcept: 默认构造函数,创建一个未初始化的条件变量对象;
  • condition_variable(const condition_variable&) = delete: 禁用复制构造函数;
  • condition_variable& operator=(const condition_variable&) = delete: 禁用赋值运算符。

# 成员函数

  • void notify_one() noexcept: 唤醒一个等待此条件变量的线程,如果有多个线程在等待,则唤醒其中一个线程,比如线程池;
  • void notify_all() noexcept: 唤醒所有等待此条件变量的线程;
  • void wait(std::unique_lock<std::mutex>& lock): 阻塞当前线程,直到收到通知,调用此函数时需要持有互斥量 lock,线程进入等待状态后,互斥量会被释放,线程被唤醒后,互斥量会被重新锁定;
  • template <class Predicate> void wait(std::unique_lock<std::mutex>& lock, Predicate pred): 阻塞当前线程,直到收到通知并且条件 pred 返回 true,调用此函数时需要持有互斥量 lock,线程进入等待状态后,互斥量会被释放,线程被唤醒后,互斥量会被重新锁定,并且检查条件 pred 是否满足;
  • template <class Rep, class Period> std::cv_status wait_for(std::unique_lock<std::mutex>& lock, const std::chrono::duration<Rep, Period>& rel_time): 阻塞当前线程,直到收到通知或者超时,调用此函数时需要持有互斥量 lock,线程进入等待状态后,互斥量会被释放,线程被唤醒或超时后,互斥量会被重新锁定;
  • template <class Rep, class Period, class Predicate> bool wait_for(std::unique_lock<std::mutex>& lock, const std::chrono::duration<Rep, Period>& rel_time, Predicate pred): 阻塞当前线程,直到收到通知、超时或者条件 pred 返回 true,调用此函数时需要持有互斥量 lock,线程进入等待状态后,互斥量会被释放,线程被唤醒、超时后,互斥量会被重新锁定,并且检查条件 pred 是否满足;
  • template <class Clock, class Duration> std::cv_status wait_until(std::unique_lock<std::mutex>& lock, const std::chrono::time_point<Clock, Duration>& abs_time): 阻塞当前线程,直到收到通知或者到达指定时间点,调用此函数时需要持有互斥量 lock,线程进入等待状态后,互斥量会被释放。线程被唤醒或时间点到达后,互斥量会被重新锁定;
  • template <class Clock, class Duration, class Predicate> bool wait_until(std::unique_lock<std::mutex>& lock, const std::chrono::time_point<Clock, Duration>& abs_time, Predicate pred): 阻塞当前线程,直到收到通知、到达指定时间点或者条件 pred 返回 true。调用此函数需要持有互斥量 lock,线程进入等待状态后,互斥量会被释放。线程被唤醒、时间点到达后,互斥量会被重新锁定,并检查条件 pred 是否满足。

#include <iostream>
#include <vector>
#include <thread>
#include <queue>
#include <future>
#include <functional>
#include <condition_variable>
 
class ThreadPool {
public:
    ThreadPool(size_t numThreads);
    ~ThreadPool();
 
    template <class F, class... Args>
    auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>;
 
private:
    std::vector<std::thread> workers;  // 工作线程
    std::queue<std::function<void()>> tasks;  // 任务队列
    std::mutex queueMutex;  // 任务队列的互斥锁
    std::condition_variable condition;  // 条件变量,用于通知工作线程有任务可执行
    bool stop;  // 标记线程池是否停止
};
 
// 构造函数:创建指定数量的线程,并让它们等待任务
ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
    for (size_t i = 0; i < numThreads; ++i) {
        workers.emplace_back([this] {
            while (true) {
                std::unique_lock<std::mutex> lock(this->queueMutex);
                // 如果任务队列为空则等待并释放互斥量queueMutex
                this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
                if (this->stop && this->tasks.empty()) return;
                std::function<void()> task = std::move(this->tasks.front());
                this->tasks.pop();
                task();  // 执行任务
            }
        });
    }
}
 
// 向线程池提交任务
template <class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {
    using return_type = typename std::result_of<F(Args...)>::type;
 
    auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queueMutex);
        tasks.emplace([task]() { (*task)(); });
    }
    condition.notify_one();  // 通知工作线程有任务可执行
    return res;
}
 
// 析构函数:停止所有工作线程
ThreadPool::~ThreadPool() {
    {
        std::unique_lock<std::mutex> lock(queueMutex);
        stop = true;
    }
    condition.notify_all();
    for (std::thread& worker : workers) worker.join();
}
 
int main() {
    ThreadPool pool(4);
 
    auto result = pool.enqueue([](int a, int b) { return a + b; }, 5, 10);
    std::cout << "Result: " << result.get() << std::endl;  // 输出15
 
    return 0;
}
4、自旋锁(atomic

自旋锁指的是当一个线程在获取锁的时候,如果锁已经被其他线程所获取,那么该线程就将进入一个循环,不断的去判断自身是否能够获得锁 ,直到该线程获得了锁,线程才会退出循环。

自旋锁与互斥锁一样是一个为了实现对共享资源的保护而提出的锁机制,都是为了解决对某项资源的互斥使用,它们保证了在并发过程中,该共享资源在任意一个时间端都只有一个拥有者,但是与互斥锁不同的是,自旋锁在共享资源已经被占用的情况下,该线程不会进入阻塞状态,如果自旋锁已经被其他线程所占有,此时试图调用自旋锁将进入循环状态来查看是否能不能获得该锁,而这本身也是由于两者在调度机制上有所不同所造成的。

注意: 未获取锁的线程一直没有休眠处于活跃状态,虽然它本身并不执行什么工作,但是它依旧会消耗cpu,称这种状态叫busy waitting。

在多线程编程中,多个线程可能会同时访问和修改共享数据,如果没有适当的同步机制,线程之间的干扰会导致数据竞争和不一致性,原子操作通过硬件或软件保证某个操作在执行时不会被打断,从而防止数据竞争;

在C++中,std::atomic提供了一种便捷且高效的方式来实现原子操作,以确保在多线程环境下对共享变量的操作是线程安全的,可以使用std::atomic来实现锁、计数器、标志等功能;

原子操作是多线程编程中的重要工具,提供了一种无锁的方式来实现线程安全,通过理解和正确使用原子操作,可以编写出高效且安全的多线程代码,C++中的std::atomic类型和相关操作使得原子操作的使用变得更加方便和高效。

# 原子类型:

  • std::atomic<bool>:原子布尔类型
  • std::atomic<int>:原子整数类型
  • std::atomic<std::shared_ptr<T>>:原子智能指针
  • 其他整数和指针类型

加载和存储:

load():从原子变量读取值

store():向原子变量写入值

交换操作:

exchange():原子地设置变量新值,并返回旧值

比较并交换(CAS):

compare_exchange_weak():原子地比较并交换,允许弱比较

compare_exchange_strong():原子地比较并交换,强比较

算术操作:

fetch_add():原子地加法操作

fetch_sub():原子地减法操作

fetch_and():原子地按位与操作

fetch_or():原子地按位或操作

// 基于原子操作的锁(CAS锁),在两个线程中,每个线程尝试对共享变量 sum 进行操作,同时通过 CAS 类的 lock 和 unlock 方法来确保操作的原子性和线程安全。

#include <iostream>
#include <atomic>
#include <thread>

using namespace std;

class CAS {
private:
    std::atomic<bool> flag;
public:
    CAS():flag(false) {}
    CAS(const CAS&)=delete;
    CAS& operator =(const CAS&)=delete;
    
    void lock() {
        bool expect = false;
        // 判断能否获得锁
        while(!flag.compare_exchange_strong(expect, true)) {
            // 失败后,再次尝试
            expect = false;  
        }
    }
    void unlock() {
        // 解锁
        flag.store(false);   
    }
};

int sum = 0;
CAS cas;

void fun()
{
    for(int i = 0;i < 10;i++) {
        cas.lock();
        cout << "sum:" << sum++ << endl;
        cas.unlock();
    }
}

int main()
{
    std::thread t1(fun);
    std::thread t2(fun);
    t1.join();
    t2.join();
    return 0;
}

四、异步处理

c++11还提供了异步接口std::async,通过这个异步接口可以很方便的获取线程函数的执行结果,std::async会自动创建一个线程去调用 线程函数,它返回一个std::future,这个future中存储了线程函数返回的结果,当需要线程函数的结果时,直接从future中获取。

#include <future>

#include <thread>

1、std::async/std::packaged_task

async(std::launch::async | std::launch::deferred, f, args...)

std::launch::async:在调用async就开始创建线程;
std::launch::deferred:延迟加载方式创建线程,调用async时不创建线程,直到调用了future的get或者wait时才创建线程;

f:线程函数;

args:线程函数的参数。

template <typename R, typename... Args>class packaged_task;

R 是可调用对象的返回类型;

Args... 是可调用对象的参数类型。

2、std::future

std::future 是与异步任务关联对象,用于获取异步操作结果,检查任务是否完成,或者处理任务中的异常。

get():阻塞并获取任务的结果。如果任务抛出异常,get() 会重新抛出该异常;

wait():阻塞直到任务完成,但不返回结果。用于等待任务完成;

wait_for():等待任务直到指定时间(时间间隔),若任务在此时间内未完成,则返回;

wait_until():类似于 wait_for,但是等待的是一个具体的时间点。

3、std::status

std::future_status 是 C++ 标准库中用于描述 std::future 对象的当前状态的一个枚举类型,用于判断异步任务的执行状态,可以用来检查异步操作是否完成、是否超时等。

  1. std::future_status::ready:表示异步任务已经完成,可以获取结果。任务已经执行完毕,调用 get() 或 wait() 都不会阻塞线程;
  2. std::future_status::timeout:表示等待的时间已经超过了指定的最大时间,但异步任务仍然没有完成。通常是使用 wait_for 或 wait_until 来进行时间控制时,会遇到此状态;std::future_status::deferred:表示任务被延迟执行,只有在显式调用 get() 或 wait() 时,任务才会开始执行,这是 std::launch::deferred 启动策略的标志。
4、示例代码

std::async:

#include <iostream>

#include <future>

#include <thread>

#include <chrono>

int main() {

    // 示例 1:简单的返回值

    std::future<int> f1 = std::async(std::launch::async, []() { return 8; });

    std::cout << "f1 result: " << f1.get() << std::endl;  // 输出: 8

    // 示例 2:无返回值的异步任务

    std::future<void> f2 = std::async(std::launch::async, []() {

        std::cout << "f2 prints: 8" << std::endl;  // 输出: 8

    });

    f2.wait();  // 等待 f2 完成

    // 示例 3:带有延时的异步任务

    std::future<int> future = std::async(std::launch::async, []() {

        std::this_thread::sleep_for(std::chrono::seconds(3));  // 模拟任务延时

        return 8;  // 返回值 8

    });

    std::cout << "waiting...\n";  // 主线程等待

    std::future_status status;

    // 使用 while 循环不断检查任务的状态

    do {

        status = future.wait_for(std::chrono::seconds(1));  // 每秒检查一次

        if (status == std::future_status::deferred) {

            std::cout << "Status: deferred\n";  // 如果任务被延迟

        } else if (status == std::future_status::timeout) {

            std::cout << "Status: timeout (still waiting)\n";  // 如果任务超时未完成

        } else if (status == std::future_status::ready) {

            std::cout << "Status: ready (task completed)\n";  // 如果任务已完成

        }

    } while (status != std::future_status::ready);  // 直到任务完成

    // 获取任务的结果并输出

    std::cout << "Result: " << future.get() << '\n';  // 输出任务的返回值: 8

    return 0;

}

std::packaged_task:

#include <iostream>

#include <thread>

#include <future>

std::string promise_string(std::string str)

{

    for (int i = 0; i < 100; i++) {

        std::this_thread::sleep_for(std::chrono::milliseconds(10));

        std::cout << "sleep" << std::endl;

    }

    std::string str1 = "the current function name is ";

    str1.append(__FUNCTION__);

    return str + str1;

}

int main()

{

    std::packaged_task<std::string(std::string)> pTask(promise_string);

    std::future<std::string> fu = pTask.get_future();

    std::thread tr(std::move(pTask),"测试 ");

    std::string strR = fu.get();

    std::cout << "the result is:" << strR.c_str() << std::endl;

    tr.join();

    system("pause");

}

五、线程池

传统的多线程编程中,为每个任务创建和销毁线程时,这会引入较高的开销,因为线程创建、销毁和上下文切换都是昂贵的操作;

线程池(Thread Pool)是一种线程管理机制,主要用于限制系统中线程的数量、重用线程资源以及减少线程频繁创建和销毁的开销,通过维护一个线程集合(通常是固定数量的工作线程),让这些线程来执行任务而不必为每个任务都创建一个新线程,适用于频繁创建/销毁异步任务。

线程池的核心组件

  1. 任务队列:保存需要执行的任务,通常是一个线程安全的队列(如 std::queue 或 std::deque);
  2. 工作线程:线程池中预先创建的线程,用于从任务队列中取任务并执行;
  3. 任务提交接口:用于提交任务到线程池,通常使用 std::function<void()> 或 std::packaged_task 等形式来封装任务;
  4. 同步机制:用来协调任务队列和工作线程,如互斥锁(std::mutex)和条件变量(std::condition_variable)。

#include <iostream>
#include <vector>
#include <thread>
#include <queue>
#include <future>
#include <functional>
#include <condition_variable>
 
class ThreadPool {
public:
    ThreadPool(size_t numThreads);
    ~ThreadPool();
 
    template <class F, class... Args>
    auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>;
 
private:
    std::vector<std::thread> workers;  // 工作线程
    std::queue<std::function<void()>> tasks;  // 任务队列
    std::mutex queueMutex;  // 任务队列的互斥锁
    std::condition_variable condition;  // 条件变量,用于通知工作线程有任务可执行
    bool stop;  // 标记线程池是否停止
};
 
// 构造函数:创建指定数量的线程,并让它们等待任务
ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
    for (size_t i = 0; i < numThreads; ++i) {
        workers.emplace_back([this] {
            while (true) {
                std::unique_lock<std::mutex> lock(this->queueMutex);
                this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
                if (this->stop && this->tasks.empty()) return;
                std::function<void()> task = std::move(this->tasks.front());
                this->tasks.pop();
// 释放任务队列锁 - 防止阻塞其他任务导致顺序执行
lock.unlock();
                task();  // 执行任务
            }
        });
    }
}
 
// 向线程池提交任务
template <class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {
    using return_type = typename std::result_of<F(Args...)>::type;
 
    auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queueMutex);
        tasks.emplace([task]() { (*task)(); });
    }
    condition.notify_one();  // 通知工作线程有任务可执行
    return res;
}
 
// 析构函数:停止所有工作线程
ThreadPool::~ThreadPool() {
    {
        std::unique_lock<std::mutex> lock(queueMutex);
        stop = true;
    }
    condition.notify_all();
    for (std::thread& worker : workers) worker.join();
}
 
int main() {
    ThreadPool pool(4);
 
    auto result = pool.enqueue([](int a, int b) { return a + b; }, 5, 10);
    std::cout << "Result: " << result.get() << std::endl;  // 输出15
 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值