目录
3、std::thread和std::async创建线程区别
一、windows下多线程函数
1、CreateThread创建线程的过程如下:
C++多线程编程(真实入门!)_Kprogram的博客-CSDN博客_c++多线程编程
2、 _beginthread()创建线程过程如下:
C++多线程——_beginthread()和_beginthreadex_xuanyin235的专栏-CSDN博客
/*************************************************************************************************************/
二、C++接口跨平台接口
/******************C++11中添加了新的线程创建使用方法,常见的介绍如下***************************/
1、使用std::async创建多线程
std::async创建函数如下:
template<typename _Fn, typename... _Args>
future<__async_result_of<_Fn, _Args...>>
async(launch __policy, _Fn&& __fn, _Args&&... __args);
async的第一个参数launch为std::launch::async时,创建的任务会创建新的子线程;当第一个函数是std::launch::std::launch时,async不创建新线程,线程为async所在线程。
(1) 利用std::async异步线程创建过程见:c++11多线程编程(九):std::async介绍与实例_小麒麟的成长之路-CSDN博客_std::async
(2) 利用std::future获取异步线程函数执行结果:
c++11多线程编程(九):std::async介绍与实例_小麒麟的成长之路-CSDN博客_std::async
2、使用std::thread类方法创建多线程
(1)join() 主线程等待创建的子线程运行结束。
join线程的使用场景是:调用join的函数必须等待join的线程函数执行完成,才可以进行往下执行,否则阻塞调用join函数的线程,直到join线程执行完毕。
(2)detach() 主线程与创建的子线程分离,主线程不等待子线程运行结束.
利用detach函数创建线程,detach使用场景:detach()函数会让线程在后台运行,即说明主线程不会等待子线程运行结束才结束。 需要注意的是detach中如果用到了主线程中的变量,需要进行深拷贝,保证使用的变量生命周期没有结束。
3、std::thread和std::async创建线程区别
(1)std::async函数可以跟std::future<T>组合获取线程的执行结果,创建时可能创建新线程,或者不创建新线程(跟async的第一个参数有关)。
(2)std::thread类肯定会创建多线程,如果需要捕获线程中执行结果,可以在线程中将变量赋值给全局变量。
4、std::thread类创建多线程demo
join的用法demo如下:
#include <iostream>
#include <thread>
#include <stdio.h>
#include <vector>
#include <Windows.h>
void func() {
for (int i = 0; i < 10; ++i) {
char chIn[50];
sprintf_s(chIn, 49, "thread::func is : %d", i); //sprintf_s(chIn, 49, "thread::func is : %d\n", i);
OutputDebugStringA(chIn);//调试控制台打印结果
std::cout << "thread::func" << chIn << std::endl; //dos命令窗口打印
}
}
int main(int argc, char *argv[])
{
std::vector<std::thread> threads; //存储线程函数的变量
for (int i = 0; i < 10; i++) {
threads.push_back(std::thread(func));
}
for (auto &thread : threads) {
thread.join(); //执行线程变量中的每个线程执行函数
}
std::thread myFun(func);
myFun.join();
return 0;
}
思考:若线程函数使用同一个vector类型的变量进行写操作,会出现资源写入冲突的问题,若使用map代替就不会出现,因为map的键只能唯一;当然,在vector写入的时候加入锁也是可以解决的,但是加锁,在线程处理结果不能立即返回的情况下,会影响性能。程序如下:
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <map>
#include <Windows.h>
using namespace std;
std::vector<int> vecGa;
std::map<int,int> mapGa;
std::mutex va1;
void fun1(int a)
{
//std::lock_guard<std::mutex>lock(va1); // 若不加锁,vector写入时会出现访问异常的问题
//{
// Sleep(100);
// std::cout << "iiiiiiiiiiiii " << a << std::endl;
// vecGa.push_back(a);
//}
Sleep(100);
std::cout << "iiiiiiiiiiiii " << a << std::endl;
mapGa.insert(pair<int,int>(a,a));
}
int main()
{
std::vector<std::thread>vecTest;
for (int i = 0; i < 100; i++)
{
vecTest.push_back(std::thread(fun1,i));
}
for (auto &thread : vecTest)
{
thread.join();
}
std::cout << "Hello World!\n";
}
注:多线程共享相同的变量时,存在两种情况:
(1)若线程间都是共同读取一个变量,即访问同一块地址,由于都不会改写该内存的数据,所以不会产生数据修改的竞争,不需要加锁。
(2)若线程间共同修改同一个变量,即修改同一块地址的数据,会出现数据修改的竞争问题,都要加锁。
如:
nNum = 0; thread1: { nNum =+2;} thread2:{nNum=+5;}
当thread1运行到修改nNum++时,线程执行的碎片时间到, thread2获取执行权,nNum值变 为5,这时thread1获取到执行权,这时,thread1里面的变量已经变为了5,执行++操作后,变 为7,这个预期是不相符的。为了保证数据执行的顺序按照预期,可以加锁。
(局部变量的创建修改是不用加锁的,因为每个线程里面的局部变量地址是不一样的;公有变量的地址是一样的,所以修改公有变量时必须加锁)
若是想安装交替执行可以使用条件变量std::condition_variable ,参考多线程mute/lock_guard/unique_lock/condition_variable访问同一公共资源_hanxiaoyong_的博客-CSDN博客
下面举一个例子
// MutTV.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <map>
#include <Windows.h>
using namespace std;
std::mutex va1;
int nNum = 0;
void fun1(int a)
{
{std::lock_guard<std::mutex>lock(va1);
Sleep(100);
nNum += 2;
std::cout << "iiiiiiiiiiiii " << nNum << std::endl;
}
}
void fun2(int a)
{
std::lock_guard<std::mutex>lock(va1);
{
Sleep(100);
nNum += 5;
std::cout << "jjjjjjjjjjjjjjjjj " << nNum << std::endl;
}
}
int main()
{
std::vector<std::thread>vecTest;
for (int i = 0; i < 100; i++)
{
if (i < 50) {
vecTest.push_back(std::thread(fun1, i));
}
else
{
vecTest.push_back(std::thread(fun2, i));
}
}
for (auto &thread : vecTest)
{
thread.join();
}
std::cout << "Hello World!\n";
}
加锁运行情况如下:
不加锁的运行如下:
thread的线程函数绑定类成员函数如下:
#include <thread>
class A
{
void func1(int nValue)
{
//todo
}
};
void main()
{
A a;
std::thread ths(&Task::func1, &a, 1);
ths.detach();
reutrn;
}
5、多线程的应用
(1)多线程函数中若函数参数为引用,则需要使用std::ref(var)。若常引用,使用std::cref(var),具体可参考:
c++ 中ref关键字的应用_c++ ref_qzy0621的博客-CSDN博客
(2)生产者消费者的多线程模式:生产者消费者模式(c++)_c++ 生产者消费者模式_WolfOnTheWay的博客-CSDN博客
附加知识
创建线程demo可以参考如下链接: