当前位置: 首页 > news >正文

淘客做网站海棠网站注册

淘客做网站,海棠网站注册,wordpress轻社交,aso优化教程目录 一.thread类的简单介绍 二.线程函数参数 三.原子性操作库(atomic) 四.lock_guard与unique_lock 1.lock_guard 2.unique_lock 五.条件变量 一.thread类的简单介绍 在C11之前#xff0c;涉及到多线程问题#xff0c;都是和平台相关的#xff0c;比如windows和linu…目录 一.thread类的简单介绍 二.线程函数参数  三.原子性操作库(atomic) 四.lock_guard与unique_lock 1.lock_guard 2.unique_lock 五.条件变量 一.thread类的简单介绍 在C11之前涉及到多线程问题都是和平台相关的比如windows和linux下各有自己的接 口这使得代码的可移植性比较差。C11中最重要的特性就是对线程进行支持了使得C在 并行编程时不需要依赖第三方库而且在原子操作中还引入了原子类的概念。要使用标准库中的 线程必须包含 thread 头文件。 函数名功能thread()构造一个线程对象没有关联任何线程函数即没有启动任何线程thread(fn, args1, args2, ...)构造一个线程对象并关联线程函数fnargs1args2...为线程函数的参数get_id()获取线程idjionable()线程是否还在执行joinable代表的是一个正在执行中的线程。jion()该函数调用后会阻塞住线程当该线程结束后主线程继续执行detach()在创建线程对象后马上调用用于把被创建线程与线程对象分离开分离的线程变为后台线程创建的线程的死活就与主线程无关 注意 1. 线程是操作系统中的一个概念线程对象可以关联一个线程用来控制线程以及获取线程的 状态。 2. 当创建一个线程对象后没有提供线程函数该对象实际没有对应任何线程。 get_id()的返回值类型为id类型id类型实际为std::thread命名空间下封装的一个类该类中 包含了一个结构体  // vs下查看 typedef struct { /* thread identifier for Win32 */void* _Hnd; /* Win32 HANDLE */unsigned int _Id; } _Thrd_imp_t; 3.当创建一个线程对象后并且给线程关联线程函数该线程就被启动与主线程一起运行。 线程函数一般情况下可按照以下三种方式提供 函数指针lambda表达式函数对象 #includeiostream #includethread #includestring using namespace std;void func1(string str) {cout str endl; } struct func2 {void operator()(string str){cout str endl;} };int main() {std::thread t1(func1, 函数指针);std::thread t2(func2(), 仿函数);std::thread t3([](string str){cout str endl; }, lambda);t1.join();t2.join();t3.join();return 0; } 4. thread类是防拷贝的不允许拷贝构造以及赋值但是可以移动构造和移动赋值即将一个 线程对象关联线程的状态转移给其他线程对象转移期间不意向线程的执行。 5. 可以通过jionable()函数判断线程是否是有效的如果是以下任意情况则线程无效 采用无参构造函数构造的线程对象线程对象的状态已经转移给其他线程对象线程已经调用jion或者detach结束 二.线程函数参数  线程函数的参数是以值拷贝的方式拷贝到线程栈空间中的因此即使线程参数为引用类型在 线程中修改后也不能修改外部实参因为其实际引用的是线程栈中的拷贝而不是外部实参。 如果想要通过形参改变外部实参时必须借助std::ref()函数,或者使用指针 #include thread void ThreadFunc1(int x) {x 10; } void ThreadFunc2(int* x) {*x 10; } int main() {int a 10;int b 10;// 如果想要通过形参改变外部实参时必须借助std::ref()函数thread t2(ThreadFunc1, std::ref(a));t2.join();cout a endl;//地址的拷贝thread t3(ThreadFunc2, b);t3.join();cout b endl;return 0; } 注意如果是类成员函数作为线程参数时必须将this作为线程函数参数。 三.原子性操作库(atomic) 多线程最主要的问题是共享数据带来的问题(即线程安全)。如果共享数据都是只读的那么没问 题因为只读操作不会影响到数据更不会涉及对数据的修改所以所有线程都会获得同样的数 据。但是当一个或多个线程要修改共享数据时就会产生很多潜在的麻烦。比如 两个线程分别进行100000次的操作 #include iostream #include thread using namespace std; unsigned long sum 0;void fun(size_t num) {for (size_t i 0; i num; i)sum; } int main() {cout Before joining,sum sum std::endl;thread t1(fun, 1000000);thread t2(fun, 1000000);t1.join();t2.join();cout After joining,sum sum std::endl;return 0; } 我们首先想到的解决办法就是加锁但是加锁有一个缺陷就是只要一个线程在对sum时其他线程就会被阻塞会影响程序运行的效率而且锁如果控制不好还容易造成死锁。 因此C11中引入了原子操作。所谓原子操作即不可被中断的一个或一系列操作C11引入 的原子操作类型使得线程间数据的同步变得非常高效原子操作头文件atomic。 例如 #include iostream #include thread #includeatomic using namespace std; //unsigned long sum 0; atomic_int sum 0;void fun(size_t num) {for (size_t i 0; i num; i)sum; } int main() {cout Before joining,sum sum std::endl;thread t1(fun, 1000000);thread t2(fun, 1000000);t1.join();t2.join();cout After joining,sum sum std::endl;return 0; } 在C11中程序员不需要对原子类型变量进行加锁解锁操作线程能够对原子类型变量互斥的 访问。 更为普遍的程序员可以使用atomic类模板定义出需要的任意原子类型。 atmoicT t;   // 声明一个类型为T的原子类型变量t #include atomic int main() { atomicint a1(0); //atomicint a2(a1);  // 编译失败 atomicint a2(0); //a2 a1;        // 编译失败 return 0; } 注意原子类型通常属于资源型数据多个线程只能访问单个原子类型的拷贝因此在C11 中原子类型只能从其模板参数中进行构造不允许原子类型进行拷贝构造、移动构造以及 operator等为了防止意外标准库已经将atmoic模板类中的拷贝构造、移动构造、赋值运算 符重载默认删除掉了。 四.lock_guard与unique_lock 在多线程环境下如果想要保证某个变量的安全性只要将其设置成对应的原子类型即可即高 效又不容易出现死锁问题。但是有些情况下我们可能需要保证一段代码的安全性那么就只能 通过锁的方式来进行控制。 比如一个线程对变量number进行加一100次另外一个减一100次每次操作加一或者减一之 后输出number的结果要求number最后的值为1。  #include thread #include mutex int number 0; mutex g_lock; int ThreadProc1() {for (int i 0; i 100; i){g_lock.lock();number;cout thread 1 : number endl;g_lock.unlock();}return 0; } int ThreadProc2() {for (int i 0; i 100; i){g_lock.lock();--number;cout thread 2 : number endl;g_lock.unlock();}return 0; }int main() {thread t1(ThreadProc1);thread t2(ThreadProc2);t1.join();t2.join();cout number: number endl;system(pause);return 0; } 上述代码的缺陷锁控制不好时可能会造成死锁最常见的比如在锁中间代码返回或者在锁 的范围内抛异常。因此C11采用RAII的方式对锁进行了封装即lock_guard和unique_lock。 lock_guard定义如下 templateclass _Mutex class lock_guard { public:// 在构造lock_gard时_Mtx还没有被上锁explicit lock_guard(_Mutex _Mtx): _MyMutex(_Mtx){_MyMutex.lock();}// 在构造lock_gard时_Mtx已经被上锁此处不需要再上锁lock_guard(_Mutex _Mtx, adopt_lock_t): _MyMutex(_Mtx){}~lock_guard() _NOEXCEPT{_MyMutex.unlock();}lock_guard(const lock_guard) delete;lock_guard operator(const lock_guard) delete; private:_Mutex _MyMutex; }; 1.lock_guard 通过上述代码可以看到lock_guard类模板主要是通过RAII的方式对其管理的互斥量进行了封 装在需要加锁的地方只需要用上述介绍的任意互斥体实例化一个lock_guard调用构造函数 成功上锁出作用域前lock_guard对象要被销毁调用析构函数自动解锁可以有效避免死锁 问题。 改造上述代码 #include thread #include mutex int number 0; mutex g_lock; int ThreadProc1() {for (int i 0; i 100; i){lock_guardmutex lock(g_lock);//调用构造加锁出作用域自动解锁number;cout thread 1 : number endl;}return 0; } int ThreadProc2() {for (int i 0; i 100; i){lock_guardmutex lock(g_lock);//调用构造加锁出作用域自动解锁--number;cout thread 2 : number endl;}return 0; }int main() {thread t1(ThreadProc1);thread t2(ThreadProc2);t1.join();t2.join();cout number: number endl;system(pause);return 0; } lock_guard的缺陷太单一用户没有办法对该锁进行控制因此C11又提供了unique_lock。 2.unique_lock 与lock_gard类似unique_lock类模板也是采用RAII的方式对锁进行了封装并且也是以独占所有权的方式管理mutex对象的上锁和解锁操作即其对象之间不能发生拷贝。在构造(或移动(move)赋值)时unique_lock 对象需要传递一个 Mutex 对象作为它的参数新创建的unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作。使用以上类型互斥量实例化unique_lock的对象时自动调用构造函数上锁unique_lock对象销毁时自动调用析构函数解锁可以很方便的防止死锁问题。  与lock_guard不同的是unique_lock更加的灵活提供了更多的成员函数 上锁/解锁操作lock、try_lock、try_lock_for、try_lock_until和unlock。修改操作移动赋值、交换(swap与另一个unique_lock对象互换所管理的互斥量所有权)、释放(release返回它所管理的互斥量对象的指针并释放所有权)。获取属性owns_lock(返回当前对象是否上了锁)、operator bool()(与owns_lock()的功能相同)、mutex(返回当前unique_lock所管理的互斥量的指针)。 五.条件变量 对条件变量的熟悉我们linux互斥与同步已经讲过了他们用来进行线程之间的互相通知。condition_variable和Linux posix的条件变量并没有什么大的区别主要还是面向对象实现的。 例如使用两个线程两个线程交替打印奇数和偶数 #includemutex #includecondition_variable mutex g_lock;//锁 condition_variable cond;//条件变量int num 1;//打印奇数 void Func1(int n) {for (int i 1; i n; i){unique_lockmutex mutex(g_lock);if (num % 2 0){cond.wait(mutex);}cout thread1: num endl;cond.notify_one();} }//打印偶数 void Func2(int n) {for (int i 1; i n; i){unique_lockmutex mutex(g_lock);if (num % 2 1){cond.wait(mutex);}cout thread2: num endl;cond.notify_one();} } int main() {thread t1(Func1, 100);thread t2(Func2, 100);t1.join();t2.join();return 0; }
http://www.w-s-a.com/news/95441/

相关文章:

  • 请人做游戏的网站视觉设计师的工作内容
  • 昆明网站建设知名企业博客网站开发
  • 如何做网站网页免费thinkphp网站后台模板
  • 怎么自己做优惠券网站济南小程序开发
  • 南昌网站专业制作做仿站如何获取网站源码
  • qq钓鱼网站wordpress 企业站模板
  • 推进文明网站建设免费设计公司logo设计
  • 做电脑租赁网站server 2008 网站部署
  • 做网站的公司一年能赚多少钱wordpress作者增加分类插件
  • 苏州尚云网站建设专业摄影网站推荐
  • 020网站开发微信公众号直接链接网站怎么做
  • 学做烘焙的网站某网站注册需要邮箱是怎么弄
  • 网站的特效代码公司网站开发的工作内容
  • 网站制作哪家好商城网站建设预算要多少钱
  • 怎么做律所的官方网站微网站可以做商城吗
  • 通用网站后台管理系统(php版)网站备案ip查询网站查询
  • 制作网站代码吗江阴网站建设推广
  • 汕头建网站wordpress文章网址采集
  • 十大景观设计网站用vue框架做的网站
  • 福建省建设监理网官方网站做外贸网站卖什么东西好
  • 公司做网站排名东莞关键词优化推广
  • 连云港做企业网站公司全网营销与seo
  • 电子毕业设计代做网站wordpress 插件放在那
  • 黄石规划建设局网站怎么做存储网站
  • 网站安装wordpress滨江网站建设
  • 河南官网网站建设一般使用的分辨率显示密度是
  • dedecms新网站 上传到万网的空间宝洁公司网站做的怎么样
  • 网站建设语录优惠券的网站怎么做的
  • 白山市住房和建设局网站有实力高端网站设计地址
  • 沧州网站建设制作设计优化深圳网站自然优化