郑州品牌网站建设费用,嘉兴百度快照优化排名,佛山市桂城建设局网站,深圳 环保 骏域网站建设专家这篇文章接着上一篇#xff0c;继续介绍C中的多线程。
推荐先阅读上一篇 【C】多线程#xff08;一#xff09;#xff1a;std::thread的使用
互斥
我们前面的函数#xff0c;无论是线程之间#xff0c;还是线程和主线程之间#xff0c;都是没有数据交换的。 接下来让…这篇文章接着上一篇继续介绍C中的多线程。
推荐先阅读上一篇 【C】多线程一std::thread的使用
互斥
我们前面的函数无论是线程之间还是线程和主线程之间都是没有数据交换的。 接下来让多个线程操作一个全局变量试试。
int global_num 0;void plus1000()
{for (int i 0; i 1000; i)global_num;
}int main()
{thread ths[10];for (auto th : ths)th thread(plus1000);for (auto th : ths)th.join();cout n global_num endl;return 0;
}运行结果并不是固定的很奇怪。只有第一次出现了结果异常的后续都是正常的。即使我把生成的 exe 删掉结果也是正常的。
[Running] cd d:\Codes\CPP\VSCodeProjects\Nov\ThreadTest\ g ThreadTest.cpp -o ThreadTest d:\Codes\CPP\VSCodeProjects\Nov\ThreadTest\ThreadTest
n 9059[Done] exited with code0 in 3.399 seconds[Running] cd d:\Codes\CPP\VSCodeProjects\Nov\ThreadTest\ g ThreadTest.cpp -o ThreadTest d:\Codes\CPP\VSCodeProjects\Nov\ThreadTest\ThreadTest
n 10000[Done] exited with code0 in 1.189 seconds[Running] cd d:\Codes\CPP\VSCodeProjects\Nov\ThreadTest\ g ThreadTest.cpp -o ThreadTest d:\Codes\CPP\VSCodeProjects\Nov\ThreadTest\ThreadTest
n 10000如果这里针对全局变量的操作是单线程的就不会有数据异常的问题。要解决这个问题需要用到两个变量。
std::mutex
mutex又称互斥量C 11中与 mutex相关的类包括锁类型和函数都声明在 mutex 头文件中所以如果你需要使用 std::mutex就必须包含 mutex 头文件。然后在适当的地方声明一个 mutex 变量即可。
mutex mtx;在操作全局变量前对 mutex 上锁操作完解锁就可以避免数据异常的问题。
void plus1000()
{for (int i 0; i 1000; i){mtx.lock();global_num;mtx.unlock();}
}
不停地加锁和解锁会消耗 CPU 的性能也会延长程序的运行时间。C 有很多对程序进行计时的函数我们这里使用 Windows 平台的一个函数。 QueryPerformanceCounter()是一个Windows API所需头文件为windows.h 这个函数返回高精确度性能计数器的值,它可以以微妙为单位计时.但是QueryPerformanceCounter() 确切的精确计时的最小单位是与系统有关的, 所以,必须要查询系统以得到QueryPerformanceCounter()返回的嘀哒声的频率. QueryPerformanceFrequency() 提供了这个频率值,返回每秒嘀哒声的个数. void plus1000()
{for (int i 0; i 1000; i){mtx.lock();global_num;mtx.unlock();}
}int main()
{LARGE_INTEGER t1,t2,tc;QueryPerformanceFrequency(tc);QueryPerformanceCounter(t1);thread ths[10];for (auto th : ths)th thread(plus1000);for (auto th : ths)th.join();QueryPerformanceCounter(t2);cout n global_num , total time (double)(t2.QuadPart-t1.QuadPart)/(double)tc.QuadPart endl;return 0;
}输出的结果为
n 10000, total time 0.0003675std::atomic
atom 意为 原子即不可分割的最小操作。理解这个需要一点操作系统多线程的知识。
回到 C 来说需要引入头文件atomic将 int 的声明方式改为 atomic_int 或者atomicint
atomic_int global_num 0;这两个是一样的从源代码可以看出来 /// atomic_inttypedef atomicint atomic_int;即可去掉 mutex 锁依然 能保证多线程下数据不会出现异常。这时的输出为
n 10000, total time 0.0003647感觉其实也没差多少我更愿意理解为误差。
async 异步
thread在使用的时候有个很大的问题就是没法获取函数的返回值。不过如果你是一个写过一些 C 代码的人你应该熟悉使用引用参数替代返回值的写法这里就不展开了另外功能上也没有 async 全面。
事实上thread 是一定会创建一个新的线程的但 async 不一定这在系统资源紧张的时候尤为明显此时强行创建一个新的线程有概率导致程序崩溃。总之先写个程序吧。
#include iostream
#include futureusing namespace std;int main()
{async([]{ cout Maybe a new thread? endl; });cout Yeah, u r right! endl;return 0;
}和 thread 不一样async 是个函数其声明如下 async(_Fn __fn, _Args... __args){return std::async(launch::async|launch::deferred,std::forward_Fn(__fn),std::forward_Args(__args)...);}async(launch __policy, _Fn __fn, _Args... __args)第一个参数即你希望 async 以什么样的方式执行 fun
标识符作用launch::async开启一个新线程立刻执行funlaunch::deferred不立刻执行fun而是延迟到调用获取结果get的时候再执行此时也不会开启新的线程std::launch::async or std::launch::deferred由操作系统决定采用以上哪种方式当没有传入launch参数时此为参数的默认值 /// Launch code for futuresenum class launch{async 1,deferred 2};