一、多线程概述
多线程是一种利用CPU时间分片的并发编程方式,能够提高程序的执行效率。在C++中,多线程编程需要使用一系列的线程库来完成。除了常见的std::thread,还有boost::thread、pthread、Windows API等。
在使用多线程编程时,需要注意线程安全。多个线程同时访问同一个资源,可能会发生读写冲突,导致程序异常崩溃。因此,在编写多线程程序时,需要加锁来避免这类问题。
下面是一个简单的多线程程序示例:
#include <iostream> #include <thread> void PrintMsg(int id) { std::cout << "Thread " << id << " is running\n"; } int main() { std::thread t1(PrintMsg, 1); std::thread t2(PrintMsg, 2); t1.join(); t2.join(); return 0; }
代码解释:调用PrintMsg函数的两个线程t1和t2同时启动,分别输出"Thread 1 is running"和"Thread 2 is running",最后再等待这两个线程的执行完毕。
二、线程同步
在多线程编程中,线程同步是一个非常重要的问题。线程同步指的是多个线程之间的协调和通信,以实现对共享资源的读写操作。
在C++中,线程同步的方式有多种,比如互斥锁(std::mutex)、条件变量(std::condition_variable)、原子变量(std::atomic)等。
下面是一个使用std::mutex同步的例子:
#include <iostream> #include <thread> #include <mutex> std::mutex g_lock; void PrintMsg(int id) { g_lock.lock(); std::cout << "Thread " << id << " is running\n"; g_lock.unlock(); } int main() { std::thread t1(PrintMsg, 1); std::thread t2(PrintMsg, 2); t1.join(); t2.join(); return 0; }
代码解释:使用std::mutex来保证PrintMsg函数的输出不会被多个线程同时执行,从而保证线程安全。
三、线程池
线程池是一种常见的多线程编程模型,通过创建多个线程并分配工作任务的方式,来提高程序的执行效率。
C++11中也提供了线程池相关的库,比如std::async和std::future。
下面是一个使用std::async和std::future的例子:
#include <iostream> #include <vector> #include <future> int Plus(int x, int y) { return x + y; } int main() { std::vector<std::future<int>> futures; for(int i = 0; i < 10; i++) { futures.push_back(std::async(Plus, i, i+1)); } for(auto & f : futures) { std::cout << f.get() << std::endl; } return 0; }
代码解释:将10个Plus函数的调用任务放入std::async函数中,在等待这些任务完成后,输出结果。
四、死锁问题
在多线程编程中,死锁是一个常见的问题。死锁指的是多个线程之间互相等待,导致程序无法继续执行。
死锁的解决方式主要有两种:1)避免嵌套锁;2)使用std::lock_guard来避免手动上锁和解锁。
下面是一个死锁示例:
#include <iostream> #include <thread> #include <mutex> std::mutex g_lock1, g_lock2; void A() { g_lock1.lock(); std::cout << "A locked g_lock1\n"; g_lock2.lock(); std::cout << "A locked g_lock2\n"; g_lock2.unlock(); g_lock1.unlock(); } void B() { g_lock2.lock(); std::cout << "B locked g_lock2\n"; g_lock1.lock(); std::cout << "B locked g_lock1\n"; g_lock1.unlock(); g_lock2.unlock(); } int main() { std::thread t1(A); std::thread t2(B); t1.join(); t2.join(); return 0; }
代码解释:A函数先上锁g_lock1,然后又试图上锁g_lock2;B函数先上锁g_lock2,然后又试图上锁g_lock1,导致两个线程之间互相等待,产生死锁。
五、多线程性能优化
在多线程编程中,性能优化是一个非常重要的问题。性能优化可以从多个角度来进行优化,比如减少锁竞争、提高CPU利用率、使用局部变量等。
下面是一个使用std::lock_guard和局部变量的例子来减少锁竞争:
#include <iostream> #include <vector> #include <thread> #include <mutex> std::mutex g_lock; void Add(std::vector<int> & v, int x) { std::lock_guard<std::mutex> lock(g_lock); v.push_back(x); } void Worker() { std::vector<int> v; for(int i = 0; i < 100000; i++) { Add(v, i); } } int main() { std::vector<std::thread> threads; for(int i = 0; i < 10; i++) { threads.emplace_back(Worker); } for(auto & t : threads) { t.join(); } return 0; }
代码解释:每个线程都有一个局部变量v来存储数据,然后通过Add函数来向v中添加元素。由于每个线程有自己的局部变量,因此减少了锁竞争的发生。