1. C++11 多线程编程介绍
C++11 多线程编程,是指在同一个进程内,有多个线程来执行程序代码。多线程编程的出现,使得程序能够更有效地利用计算机的多核资源,从而提高程序性能。
下面我们来看看在 C++11 中,多线程编程是如何实现的。
2. 线程的创建和启动
2.1 创建线程
在 C++11 中,创建线程可以通过 std::thread 类来实现。std::thread 类是 C++11 标准库中专门用来处理线程的类,我们可以通过 new 运算符来创建这个类的实例。
#include <iostream>
#include <thread>
using namespace std;
void my_thread_func(){
cout << "Hello from thread!" << endl;
}
int main(){
thread my_thread(my_thread_func);
my_thread.join();
return 0;
}
这段代码通过 std::thread 类创建了一个新的线程 my_thread,并调用 my_thread_func 函数来执行线程中的任务。
2.2 启动线程
调用 std::thread 的 start() 函数来启动一个线程非常直观,但是实际上,在 C++11 中并没有这个函数。
如果你曾经接触过线程编程,肯定非常熟悉调用 pthread_create() 函数来启动一个新线程。而在 C++11 中,我们启动线程的方式也与 pthread_create() 类似,可以通过调用线程实例的 join() 函数来启动线程。
join() 函数用来阻塞调用它的线程,直到另一个线程执行结束。在我们的示例程序中,我们调用了主线程的 join() 函数,使其等待 my_thread 线程结束后再继续运行。
3. 线程的同步
在多线程编程中,由于多个线程可以同时访问同一资源,导致数据的不一致性。因此,在进行多线程编程时,就需要考虑如何保证线程之间的数据一致性。
3.1 互斥量
互斥量是一种控制对共享资源访问的机制,可以保证同一时间只有一个线程能够访问共享资源,从而避免了多个线程同时对同一资源进行修改的情况。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
int count = 0;
void increase_count(){
for(int i=0; i<1000000; i++){
mtx.lock();
count++;
mtx.unlock();
}
}
int main(){
thread t1(increase_count), t2(increase_count);
t1.join();
t2.join();
cout << "Count: " << count << endl;
}
这段代码通过 std::mutex 类来实现互斥锁。在 increase_count 函数中,我们使用 mutex.lock() 函数来获得锁,使用 mutex.unlock() 函数来释放锁。这样就保证了同一时间内只有一个线程能够访问 count 变量,从而避免了数据不一致的情况。
3.2 条件变量
条件变量是一种更高级的同步机制,它允许线程在某个条件达成之前等待,从而避免了线程在等待时消耗 CPU 时间的情况。条件变量通常和互斥量一起使用,在等待条件满足时,线程解锁互斥量,进入等待状态;当条件满足时,线程再次加锁互斥量。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
mutex mtx;
condition_variable cv;
bool ready = false;
void print_number(int num){
unique_lock<mutex> lock(mtx);
while(!ready){
cv.wait(lock);
}
cout << num << endl;
}
int main(){
thread threads[10];
for(int i=0; i<10; i++){
threads[i] = thread(print_number, i);
}
ready = true;
cv.notify_all();
for(int i=0; i<10; i++){
threads[i].join();
}
return 0;
}
这段代码通过 std::condition_variable 类来实现条件变量。在 print_number 函数中,我们通过 cv.wait(lock) 函数来等待条件变量 ready 的值为 true。在主函数中,我们将 ready 的值设为 true,并通过 cv.notify_all() 函数来激活所有等待条件变量的线程。
4. 线程的销毁
在线程运行结束后,需要及时地销毁线程以释放内存资源。
在线程运行结束后,线程实例中存储的线程的状态并没有释放。因此,我们需要显式地销毁线程以释放内存资源。
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
void my_thread_func(){
cout << "Thread started!" << endl;
this_thread::sleep_for(chrono::seconds(3));
cout << "Thread ended!" << endl;
}
int main(){
thread my_thread(my_thread_func);
cout << "Main thread started!" << endl;
this_thread::sleep_for(chrono::seconds(1));
my_thread.detach();
if(my_thread.joinable()){
my_thread.join();
}
cout << "Main thread ended!" << endl;
return 0;
}
这段代码通过 std::thread 类来创建线程,并通过调用 detach() 函数来分离线程。分离线程的作用是让线程独立地运行,不再依赖于主线程。在主线程结束后,分离的线程仍然继续运行直到其结束。
5. 总结
C++11 多线程编程是一项非常复杂且核心的技术,需要仔细地掌握。本文介绍了 C++11 多线程编程的基础知识,包括线程的创建、启动、同步和销毁。希望通过本文的介绍,能够帮助读者更好地理解 C++11 中的多线程编程。