今天用c++写了一些多线程的代码,写之前感觉c线程同步中用到互斥锁,条件变量等使用起来比较麻烦,于是就自己把c中的互斥锁,还有条件变量封装了一遍,封完之后在c++11相关书中查看东西时,偶然发现原来我重复造了轮子,这些c++11早就为我们准备妥当了,哪还要自己去封。。。
接下来就总结一下,刚学来的c++11对多线程开发的知识
1.线程
(1)线程创建
c++11创建线程相当容易,只需将线程类std::thread创建并初始话即可
具体实例如下
#include <iostream>
#include <thread>
void thread_worker(int n)
{
std::cout<<"n = "<<n<<std::endl;
}
int main(int argc,char **argv)
{
std::thread t(thread_worker,5);//创建线程对象t
t.join();阻塞线程t,直到其结束
return 0;
}
注意编译时要加线程库 -pthread
(2)线程传参
上述代码中,我们在初始化线程对象t是,首先第一个参数为线程函数的函数指针,其次便是线程函数的参数,如果线程有多个参数的话,我们只需按照参数顺序直接一次写到线程函数指针之后即可,具体实例如下
#include <iostream>
#include <thread>
#include <string>
void thread_worker(int n,std::string s,int m)
{
std::cout<<"n = "<<n<<std::endl;
std::cout<<"s = "<<s<<std::endl;
std::cout<<"m = "<<m<<std::endl;
}
int main(int argc,char **argv)
{
std::thread t(thread_worker,5,"shreck",6);
t.join();
return 0;
}
(3)线程阻塞
(1)中线程对象的join成员函数会阻塞在那,知道线程执行完毕,用于回收线程结束状态,如果我们不想回收线程状态,可以直接调用detach使线程和对象分离,这样做的话我们就不会知道线程何时会执行完毕
具体实例如下
#include <iostream>
#include <thread>
#include <string>
#include <unistd.h>
void thread_worker(int n,std::string s,int m)
{
std::cout<<"n = "<<n<<std::endl;
std::cout<<"s = "<<s<<std::endl;
std::cout<<"m = "<<m<<std::endl;
}
int main(int argc,char **argv)
{
std::thread t(thread_worker,5,"shreck",6);
t.detach();
sleep(1);
return 0;
}
上述代码之所以要在分离之后暂停1s是因为我的机器老是主线程先于子线程执行,导致子线程还没打印呢,主线程以退出,对应的子线程也退出了(详细知识请查看我之前有关与线程总结的博文)
2互斥量
(1)std::mutex类
C++11使用互斥量,相比c变得十分简单,它将c互斥量的操作封装与std::mutex类中,该类具体使用如下
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
int sum = 0;
std::mutex g_lock; //创建互斥锁对象
void thread_worker(int thread_number)
{
while(1)
{
g_lock.lock();//加锁
sum++;
std::cout<<"线程"<<thread_number<<":sum = "<<sum<<std::endl;
g_lock.unlock();//解锁
}
}
int main(int argc,char **argv)
{
std::thread t1(thread_worker,1);
std::thread t2(thread_worker,2);
std::thread t3(thread_worker,3);
t1.join();
t2.join();
t3.join();
return 0;
}
(2)std::lock_guard类
除了std::mutex类之外,c++11还为我们提供了更好用,也更安全的互斥锁类std::lock_guard,这个类运用了RALL技术(利用c++的构造函数分配资源,析构函数来释放资源),使我们免去了(1)中释放锁的过程,要知道我们平时写程序,上完锁之后很可能忘记释放锁,这是很可怕的问题,所以为了安全起见,我们最好使用此类
其具体用法如下
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
int sum = 0;
std::mutex g_lock; //创建互斥锁对象
void thread_worker(int thread_number)
{
while(1)
{
//用g_lock初始化此类
std::lock_guard<std::mutex> guard(g_lock);
sum++;
std::cout<<"线程"<<thread_number<<":sum = "<<sum<<std::endl;
}
}
int main(int argc,char **argv)
{
std::thread t1(thread_worker,1);
std::thread t2(thread_worker,2);
std::thread t3(thread_worker,3);
t1.join();
t2.join();
t3.join();
return 0;
}
3.条件变量
C++11中同样也封装了对条件变量使用的类,在这里我只为大家介绍一种最通用的类
(1)std::condition_variable_any
使用实例如下
#include <thread>
#include <stdio.h>
#include <mutex>
#include <condition_variable>
int sum = 0;
std::mutex g_lock;
std::condition_variable_any condtion;
void work(int n)
{
while(1)
{
std::lock_guard<std::mutex> guard(g_lock);
sum++;
printf("%d:被加到%d\n",n,sum);
condtion.notify_one();
}
}
int main(void)
{
std::thread t1(work,1);
std::thread t2(work,2);
std::thread t3(work,3);
while(1)
{
std::lock_guard<std::mutex> guard(g_lock);
//传入互斥锁g_lock
condtion.wait(g_lock);
while(sum > 0)
{
sum--;
}
printf("sum被减为sum = %d\n",sum);
}
return 0;
}
4.总结
之前也会用到C++11的一些东西,但没有系统的查看,通过这次的教训,我想我们应该好好的看看c++11的新特性,以防止再次造轮子,同时c++11给我们的接口也更为简单好用