本篇文章我们来介绍一下C++ 多进程 多线程的技术
1.为什要学习多线程 多进程
- 提高程序的性能:进程和线程可以使程序并发执行,从而充分利用计算机的多核处理器和资源,提高程序的执行效率和吞吐量。
- 实现复杂任务:通过将任务划分为多个子任务,每个子任务由一个线程或进程处理,可以更好地组织和管理代码。这样可以降低代码的复杂性,并且易于调试和维护。
- 支持并发编程:进程和线程是实现并发编程的基础。并发编程可以让多个任务在同一时间段内交替执行,提供更好的用户体验,例如同时响应用户输入、处理网络请求等。
- 充分利用系统资源:操作系统以及底层硬件通常采用多进程或多线程的方式来管理资源。了解进程和线程的工作原理可以帮助我们更好地使用系统资源,避免资源竞争和浪费。
- 解决共享数据问题:在多线程编程中,需要考虑到共享数据访问时可能出现的竞争条件。了解进程和线程之间的通信与同步机制可以帮助我们设计安全可靠的并发程序。
例如游戏服务器
多线程能够很好的处理多个玩家的问题 可以有效地避免阻塞
处理器处理只需要几毫秒的时间 就算玩家的请求比服务器多 也可以快速的提供服务
2.如何实现多线程
进程:执行起来的可运行程序
主线程 :每一个进程产生的一个线程
多线程实现案例:
#include <iostream> #include <thread> // 线程函数,计算从start到end的平方和 void squareSum(int start, int end, long long& result) { result = 0; for (int i = start; i <= end; ++i) { result += i * i; } } int main() { long long sum1 = 0, sum2 = 0; // 创建两个线程分别计算1-5和6-10的平方和 std::thread thread1(squareSum, 1, 5, std::ref(sum1)); std::thread thread2(squareSum, 6, 10, std::ref(sum2)); // 等待两个线程执行完毕 thread1.join(); thread2.join(); // 输出结果 std::cout << "Sum of squares from 1 to 5: " << sum1 << std::endl; std::cout << "Sum of squares from 6 to 10: " << sum2 << std::endl; std::cout << "Total sum: " << sum1 + sum2 << std::endl; return 0; }
在这个案例中,我们使用
std::thread
库创建了两个线程,分别计算从1到5和从6到10的平方和。每个线程将自己的结果存储在一个引用参数中。然后,通过调用join()
函数等待两个线程执行完毕,并将最终结果输出到控制台。需要注意的是,在多线程编程中,我们需要考虑到共享数据访问时可能出现的竞争条件。为了避免潜在的问题,可以使用互斥锁(
std::mutex
)或其他同步机制来确保线程安全。
3.互斥锁 线程池等知识
互斥锁(Mutex)是一种用于多线程编程的同步机制,它可以防止多个线程同时访问共享资源导致的竞争条件。
线程池(Thread Pool)是一种用于管理和复用线程的技术,它可以提供更高效的线程管理和任务调度机制。
在多线程编程中,创建和销毁线程是比较耗费资源的操作。而且,频繁地创建和销毁线程可能导致系统性能下降。线程池的思想就是将一组预先创建好的线程放入一个池中,并维护这些线程的生命周期。当有任务需要执行时,从线程池中获取一个空闲的线程来执行任务,完成后再放回线程池以便复用。
互斥锁代码实例:
#include <iostream> #include <thread> #include <mutex> std::mutex mtx; // 定义一个互斥锁 int sharedData = 0; void updateData() { std::lock_guard<std::mutex> lock(mtx); // 使用lock_guard自动管理锁的加解锁过程 ++sharedData; } int main() { std::thread thread1(updateData); std::thread thread2(updateData); thread1.join(); thread2.join(); std::cout << "Shared data: " << sharedData << std::endl; return 0; }
线程池代码实例:
#include <iostream> #include <thread> #include <vector> #include <queue> #include <functional> #include <mutex> #include <condition_variable> class ThreadPool { public: ThreadPool(size_t numThreads) : stop(false) { for (size_t i = 0; i < numThreads; ++i) { threads.emplace_back([this] { while (true) { std::function<void()> task; // 获取任务 { std::unique_lock<std::mutex> lock(queueMutex); condition.wait(lock, [this]{ return stop || !tasks.empty(); }); if (stop && tasks.empty()) { return; } task = std::move(tasks.front()); tasks.pop(); } // 执行任务 task(); } }); } } template<typename F, typename... Args> void enqueue(F&& f, Args&&... args) { // 将任务包装成函数并添加到队列中 { std::unique_lock<std::mutex> lock(queueMutex); tasks.emplace([f, args...] { f(args...); }); } condition.notify_one(); // 唤醒一个线程来执行任务 } ~ThreadPool() { { std::unique_lock<std::mutex> lock(queueMutex); stop = true; } condition.notify_all(); for (std::thread& thread : threads) { thread.join(); } } private: std::vector<std::thread> threads; std::queue<std::function<void()>> tasks; std::mutex queueMutex; std::condition_variable condition; bool stop; }; // 示例任务函数 void taskFunction(int id) { std::cout << "Task " << id << " executed by thread " << std::this_thread::get_id() << std::endl; } int main() { ThreadPool pool(4); // 创建一个大小为4的线程池 // 添加10个任务到线程池中 for (int i = 0; i < 10; ++i) { pool.enqueue(taskFunction, i); } return 0; }
在上述示例中,我们首先定义了一个
ThreadPool
类,其中包含了一个存储线程对象的std::vector
容器和一个任务队列(使用std::queue
),以及相应的互斥锁和条件变量用于线程同步。在构造函数中,我们根据指定的线程数量创建了对应数量的线程,并通过Lambda表达式定义了每个线程要执行的工作。每个线程循环地从任务队列中获取任务并执行,直到停止标志被设置为true。
在
enqueue()
函数中,我们将需要执行的任务封装成一个函数,并添加到任务队列中。之后通过调用condition.notify_one()
唤醒一个空闲的线程来执行该任务。最后,在析构函数中,我们设置停止标志为true,并通过调用
condition.notify_all()
来通知所有线程停止运行。然后等待每个线程结束运行。
总结:
1.常用的线程函数 std::thread std::this_thread::sleep_for std::mutex.....
2.掌握多线程编程知识 能够帮助我们实现大型项目的制作 大并发和百万级服务器 掌握线程池 互斥锁 原子锁等知识 能够完美的实现资源节约的功能
好了 本篇文章就到这里 在这里我想向大家推荐一个课程:
https://xxetb.xetslk.com/s/2PjJ3T