0
点赞
收藏
分享

微信扫一扫

C++线程学习

奔跑的酆 2022-01-31 阅读 53

1.thread的简单使用

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

void thread01()
{
	for (int i = 0; i < 5; i++)
	{
		cout << "Thread 01 is working !" << endl;
		Sleep(100);
	}
}
void thread02()
{
	for (int i = 0; i < 5; i++)
	{
		cout << "Thread 02 is working !" << endl;
		Sleep(200);
	}
}

int main()
{
	thread task01(thread01);
	//创建一个thread类对象task01,以thread01做为一个线程创建时构造的参数,创建的线程01执行的是thread01函数中的任务
	thread task02(thread02);
	task01.join();
	//将01子线程加入,阻塞主线程,等到01运行完才进行主线程
	task02.join();
	//将02子线程加入,阻塞主线程,等到02运行完才进行主线程

	for (int i = 0; i < 5; i++)
	{
		cout << "Main thread is working !" << endl;
		Sleep(200);
	}
	system("pause");
}

子线程01,02不会互相阻塞对方,当这两个子线程都结束时才会继续主线程
在这里插入图片描述

2.线程同步

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

int a = 0;
void thread01()
{
	for (int i = 0; i < 10000000; i++)
		a++;
}


int main()
{
	thread task01(thread01);//以thread01做为一个线程创建时的参数,创建的线程01执行的是thread01函数中的任务
	for (int i = 0; i < 10000000; i++)
		a++;
	task01.join();//将01子线程加入,阻塞主线程,等到01运行完才进行主线程
	cout << a << endl;
	system("pause");
}

在这里插入图片描述
将i 设置到10000000时会出现错误结果,一次for循环的时间大于两条语句之间的间隔,可以看到,代码中全局变量i先在主线程中自加了10000000次,再在主线程中自加了10000000次,结果应是20000000,但显示的结果为13010045,推测是主线程进行了3010045次还未结束时子线程就加进来了阻塞了主线程然后执行子线程,于是将子进程设置为空函数,预计最后显示的结果为3010045
在这里插入图片描述
可以看到结果并不是我们的猜想,说明子进程的加入并不会阻塞正在进行的主线程中的操作
我们查看子进程中a++的反汇编:

a++;
00D02643  mov         eax,dword ptr [a (0D0E2D4h)]
//将内存中地址为0D0E2D4h的值mov给寄存器eax
00D02648  add         eax,1  
//将eaxadd1
00D0264B  mov         dword ptr [a (0D0E2D4h)],eax 
//将eax的值放回 0D0E2D4h中
00D02650  jmp         thread01+31h (0D02631h)  

C++为高级语言,一句自增操作在翻译成汇编语言后变成了四句
再查看主进程中a++的反汇编:

00D03C39  mov         eax,dword ptr [a (0D0E2D4h)]  
00D03C3E  add         eax,1  
00D03C41  mov         dword ptr [a (0D0E2D4h)],eax  
00D03C46  jmp         std::thread::join+47h (0D03C27h)  

可以看到a存放的寄存器的地址相同,但指令存放的地址不同。
并发为交替地进行两个以下的操作,假设每个操作执行X毫秒
当子进程加进来后,比如在执行进程1X毫秒后只执行了第一句,假设此时a为5000,然后去执行进程2执行X毫秒a自增了3000,再切换回进程1接着执行之前没有执行完的第二局,a变回5000,在进程2中自增的3000消失掉了。
这就是同步带来的问题

3.线程同步的方法

原子操作:是指线程在访问资源时确保其他线程不会访问相同的资源(让C++一行代码对应的多行汇编代码视作一个整体,要么一起执行完毕,要不一行都不执行)

for (int i = 0; i < 10000000; i++)
	{
		InterlockedAdd((long*)&a, 1);
	}

但这仅限于加法,泛化性不高
因此引入锁这个概念
在使用前先创建临界区对象,相当于去买锁
CRITICAL_SECTION g_cs;
要先初始化锁InitializeCriticalSection,使用结束了要删掉锁DeleteCriticalSection,使用锁前EnterCriticalSection加锁,使用后解锁LeaveCriticalSection;

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

int a = 0;

//创建临界区对象--等价于锁
CRITICAL_SECTION g_cs;

void thread01()
{
	for (int i = 0; i < 10000000; i++)
	{
		//进来时上锁
		EnterCriticalSection(&g_cs);
		a++;
		//出去解锁
		LeaveCriticalSection(&g_cs);
	}
}


int main()
{
	InitializeCriticalSection(&g_cs);
	thread task01(thread01);
	for (int i = 0; i < 10000000; i++)
	{
		//进来时上锁
		EnterCriticalSection(&g_cs);
		
		a++;
		//出去解锁
		LeaveCriticalSection(&g_cs);
	}
	task01.join();
	cout << a << endl;
	system("pause");
	//不使用时删掉该锁
	DeleteCriticalSection(&g_cs);
}

4.颗粒度

举报

相关推荐

0 条评论