4 windows线程

线程

线程的组成

创建线程

无参创建线程

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>

DWORD WINAPI ThreadPro(LPVOID lpParam);
DWORD WINAPI ThreadProex(LPVOID lpParam);

int main(int argc, char *argv[])
{
	DWORD dwThreadId = 0;
	HANDLE hThread;
	hThread = CreateThread(NULL, NULL, ThreadPro, NULL, 0, &dwThreadId);
	CloseHandle(hThread);//当传入的参数中有安全属性,需要使用内核对象,则需要关闭,CreateThread的第一个参数是安全属性

	HANDLE hThreadex;
	unsigned int iThreadIdex;
	hThreadex = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadProex, NULL, 0, &iThreadIdex);
	CloseHandle(hThreadex);
	for (int i = 0; i < 200; i++)
	{
		printf("world\n");
	}
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro(LPVOID lpParam)
{
	for (int i = 0; i < 200; i++)
	{
		printf("hello\n");
	}
	return 0;
}

DWORD WINAPI ThreadProex(LPVOID lpParam)
{
	for (int i = 0; i < 200; i++)
	{
		printf("_beginthreadex\n");
	}
	return 0;
}

传递参数:整形,字符串,结构体,对象

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>

DWORD WINAPI ThreadPro(LPVOID lpParam);
DWORD WINAPI ThreadProex(LPVOID lpParam);

typedef struct _coor
{
	int x;
	int y;
}Coor;

int main(int argc, char *argv[])
{
	DWORD dwThreadId = 0;
	HANDLE hThread;
	int x = 20;
	int y = 40;
	char str1[200] = "123";
	char str2[200] = "456";
	Coor coo1 = {4,5};
	Coor coo2 = {20, 80};
	hThread = CreateThread(NULL, NULL, ThreadPro, &coo1, 0, &dwThreadId);
	CloseHandle(hThread);

	HANDLE hThreadex;
	unsigned int iThreadIdex;
	hThreadex = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadProex, &coo2, 0, &iThreadIdex);
	CloseHandle(hThreadex);
	for (int i = 0; i < 200; i++)
	{
		printf("world\n");
	}
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro(LPVOID lpParam)
{
	Coor *p = (Coor *)lpParam;
	for (int i = 0; i < 200; i++)
	{
		printf("hello %d,%d\n", p->x, p->y);
	}
	return 0;
}

DWORD WINAPI ThreadProex(LPVOID lpParam)
{
	Coor *p = (Coor *)lpParam;
	for (int i = 0; i < 200; i++)
	{
		printf("_beginthreadex %d,%d\n", p->x, p->y);
	}
	return 0;
}

对象(内置对象,自定义对象)

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <string>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadPro(LPVOID lpParam);
DWORD WINAPI ThreadProex(LPVOID lpParam);

class Coor
{
public:
	Coor(int iX, int iY)
	{
		m_iX = iX;
		m_iY = iY;
	}
	
	void printCoor()
	{
		cout << m_iX << "," << m_iY << endl;
	}
private:
	int m_iX;
	int m_iY;
};

int main(int argc, char *argv[])
{
	DWORD dwThreadId = 0;
	HANDLE hThread;
	Coor coo1(4, 5) ;
	Coor coo2(20, 80);
	string str1 = "123";
	string str2 = "345";
	string *pStr3 = new string("789");
	string *pStr4 = new string("1011");
	hThread = CreateThread(NULL, NULL, ThreadPro, &coo1, 0, &dwThreadId);
	CloseHandle(hThread);

	HANDLE hThreadex;
	unsigned int iThreadIdex;
	hThreadex = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadProex, &coo2, 0, &iThreadIdex);
	CloseHandle(hThreadex);

	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro(LPVOID lpParam)
{
	Coor *p = (Coor *)lpParam;
	p->printCoor();
	return 0;
}

DWORD WINAPI ThreadProex(LPVOID lpParam)
{
	Coor *p = (Coor *)lpParam;
	p->printCoor();
	return 0;
}

 

线程优先级

当一个线程被创建,它的“线程相对优先级”默认为normal(标准)。CreateThread函数没有提供设置线程相对优先级的功能。可以调用SetThreadPriority函数设置一个线程的相对优先级。

BOOL SetThreadPriority(HANDLE hThread,   nt nPriority);    //指定的线程句柄   //线程相对优先级

 (取值对应如下)

该函数接受一个线程句柄和线程相对优先级取值,设置对应的线程的相对优先级。该线程相对优先级取值如下:

1、THREAD_PRIORITY_TIME_CRITICAL:Time-critical,关键时间(最高)

2、THREAD_PRIORITY_HIGHEST:Highest,最高(其实是“次高”)

3、THREAD_PRIORITY_ABOVE_NORMAL:Above normal,高于标准

4、THREAD_PRIORITY_NORMAL:Normal,标准

5、THREAD_PRIORITY_BELOW_NORMAL:Below normal,低于标准

6、THREAD_PRIORITY_LOWEST:Lowest,最低(其实是“次低”)

7、THREAD_PRIORITY_IDLE:Idle,空闲(最低)

你可以呼叫GetTreadPriotiry函数取得一个特定线程的相对优先级。

int GetThreadPriority(HANDLE hThread);      //函数返回上述7个取值

为了创建一个线程相对优先级不是标准的线程,比如要创建一个高于标准的线程,你可以传递CREATE_SUSPENDED参数给CreateThread,从而创建一个起始状态为“挂起”的线程,然后调用SetThreadPriority函数设置该线程的相对优先级,然后调用ResumeThread函数恢复该线程的运行

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>

DWORD WINAPI ThreadPro(LPVOID lpParam);
DWORD WINAPI ThreadProex(LPVOID lpParam);

int main(int argc, char *argv[])
{
	DWORD dwThreadId = 0;
	HANDLE hThread;
	hThread = CreateThread(NULL, NULL, ThreadPro, NULL, CREATE_SUSPENDED, &dwThreadId);//挂起
	SetThreadPriority(hThread, THREAD_PRIORITY_LOWEST);
	ResumeThread(hThread);//唤醒
	CloseHandle(hThread);

	HANDLE hThreadex;
	unsigned int iThreadIdex;
	hThreadex = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadProex, NULL, CREATE_SUSPENDED, &iThreadIdex);
	SetThreadPriority(hThreadex, THREAD_PRIORITY_TIME_CRITICAL);
	ResumeThread(hThreadex);
	CloseHandle(hThreadex);
	
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro(LPVOID lpParam)
{
	for (int i = 0; i < 200; i++)
	{
		printf("hello\n");
	}
	return 0;
}

DWORD WINAPI ThreadProex(LPVOID lpParam)
{
	for (int i = 0; i < 200; i++)
	{
		printf("_beginthreadex\n");
	}
	return 0;
}

 

进程线程优先级

Windows是一个抢断式多线程操作系统,在并发的处理的时候最基本的执行单结构是线程,而一个进程内并不是一个执行上不可分割的结构,而是由多个线程组成的。每一个线程在内核中有一个优先级顺序,这个顺序的取值范围是0-31,数字越大优先级越高。如果有任意一个高顺序的线程需要执行,Windows绝对不会执行低优先级的线程。如果低优先级的线程一直不能被执行,那么线程就被饥饿了,这个时候抢占式操作系统的特点就体现出来了。

但是为什么平时都没有注意到呢,这里很大的原因是平时绝大多数工作线程的的优先级都是基本差不多一致的,每一个线程基本都能分配到时间片。但是有的时候我们需要创建一些较高优先级或者较低优先级的线程用来完成一些特殊的任务,我们就要了解一下这个线程的优先顺序到底是如何计算出来的。

虽然说这个优先顺序的取值范围是0-31,但是你并不能直接通过API来设定优先顺序。你能够设定一个进程优先级以及一个线程优先级。下面是一个Windows的优先级对应表:

命令行设置进程启动优先级

通过任务管理器:

 

锁定进程线程优先级,TRUE 关闭优先级操作,不允许系统去改变优先级

/*
涉及API
SetPriorityClass
SetProcessPriorityBoost

REALTIME_PRIORITY_CLASS
HIGH_PRIORITY_CLASS
ABOVE_NORMAL_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS
IDLE_PRIORITY_CLASS
*/


#include <Windows.h>
#include <stdlib.h>



int main(void)
{
	STARTUPINFO si1;
	PROCESS_INFORMATION pi1;

	ZeroMemory(&si1, sizeof(si1));
	si1.cb = sizeof(si1);
	ZeroMemory(&pi1, sizeof(pi1));

	STARTUPINFO si2;
	PROCESS_INFORMATION pi2;

	ZeroMemory(&si2, sizeof(si2));
	si2.cb = sizeof(si2);
	ZeroMemory(&pi2, sizeof(pi2));

	CreateProcess(NULL, "5x_demo1.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si1, &pi1); 
	SetPriorityClass(pi1.hProcess, IDLE_PRIORITY_CLASS);
	//true:关闭动态调整
	SetProcessPriorityBoost(pi1.hProcess, true);
	CreateProcess(NULL, "5x_demo2.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si2, &pi2);
	
	SetPriorityClass(pi2.hProcess, HIGH_PRIORITY_CLASS);
	WaitForSingleObject(pi1.hProcess, INFINITE);
	WaitForSingleObject(pi2.hProcess, INFINITE);

	CloseHandle(pi1.hProcess);
	CloseHandle(pi1.hThread);

	CloseHandle(pi2.hProcess);
	CloseHandle(pi2.hThread);

	system("pause");
	return 0;
}

高优先级的进程先执行

线程对象生命周期

1.线程函数自然退出

线程函数自然退出后,调用线程中对象的析构函数

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <string>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadPro(LPVOID lpParam);
DWORD WINAPI ThreadProex(LPVOID lpParam);

class Coor
{
public:
	Coor(int iX, int iY)
	{
		m_iX = iX;
		m_iY = iY;
		cout << "构造函数:" << m_iX << "------" << m_iY << endl;
	}

	~Coor()
	{
		cout << "析构函数:" << m_iX << "||||||" << m_iY << endl;
	}

	void printCoor()
	{
		cout << m_iX << "," << m_iY << endl;
	}
private:
	int m_iX;
	int m_iY;
};

int main(int argc, char *argv[])
{
	DWORD dwThreadId = 0;
	HANDLE hThread;
	
	hThread = CreateThread(NULL, NULL, ThreadPro, NULL, 0, &dwThreadId);
	CloseHandle(hThread);

	HANDLE hThreadex;
	unsigned int iThreadIdex;
	hThreadex = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadProex, NULL, 0, &iThreadIdex);
	CloseHandle(hThreadex);
	
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro(LPVOID lpParam)
{
	Coor coo(1,2);
	return 0;
}

DWORD WINAPI ThreadProex(LPVOID lpParam)
{
	Coor coo(3, 4);
	return 0;
}

2 .ExitThread,_endthreadex终止线程

线程中的构造的对象不会调用析构函数,等进程退出后由操作系统回收

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <string>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadPro(LPVOID lpParam);
DWORD WINAPI ThreadProex(LPVOID lpParam);

class Coor
{
public:
	Coor(int iX, int iY)
	{
		m_iX = iX;
		m_iY = iY;
		cout << "构造函数:" << m_iX << "------" << m_iY << endl;
	}

	~Coor()
	{
		cout << "析构函数:" << m_iX << "||||||" << m_iY << endl;
	}

	void printCoor()
	{
		cout << m_iX << "," << m_iY << endl;
	}
private:
	int m_iX;
	int m_iY;
};

int main(int argc, char *argv[])
{
	DWORD dwThreadId = 0;
	HANDLE hThread;
	
	hThread = CreateThread(NULL, NULL, ThreadPro, NULL, 0, &dwThreadId);
	CloseHandle(hThread);

	HANDLE hThreadex;
	unsigned int iThreadIdex;
	hThreadex = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadProex, NULL, 0, &iThreadIdex);
	CloseHandle(hThreadex);
	
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro(LPVOID lpParam)
{
	Coor coo(1,2);
  ExitThread(1);
	return 0;
}

DWORD WINAPI ThreadProex(LPVOID lpParam)
{
	Coor coo(3, 4);
  _endthreadex(1);
	return 0;
}

3 TerminateThread线程,不会执行线程对象的构造和析构函数

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <string>
#include <iostream>
using namespace std;

DWORD WINAPI ThreadPro(LPVOID lpParam);
DWORD WINAPI ThreadProex(LPVOID lpParam);

class Coor
{
public:
	Coor(int iX, int iY)
	{
		m_iX = iX;
		m_iY = iY;
		cout << "构造函数:" << m_iX << "------" << m_iY << endl;
	}

	~Coor()
	{
		cout << "析构函数:" << m_iX << "||||||" << m_iY << endl;
	}

	void printCoor()
	{
		cout << m_iX << "," << m_iY << endl;
	}
private:
	int m_iX;
	int m_iY;
};

int main(int argc, char *argv[])
{
	DWORD dwThreadId = 0;
	HANDLE hThread;
	
	hThread = CreateThread(NULL, NULL, ThreadPro, NULL, 0, &dwThreadId);
  TerminateThread(hThread, 1);
	CloseHandle(hThread);

	HANDLE hThreadex;
	unsigned int iThreadIdex;
	hThreadex = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadProex, NULL, 0, &iThreadIdex);
  TerminateThread(hThreadex, 1);
	CloseHandle(hThreadex);
	
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro(LPVOID lpParam)
{
	Coor coo(1,2);
	return 0;
}

DWORD WINAPI ThreadProex(LPVOID lpParam)
{
	Coor coo(3, 4);
	return 0;
}

 4 ExitProcess进程不建议使用

 

线程基本状态

 

线程挂起后进入堵塞态

 

Sleep函数的本质是放弃当前线程在CPU的时间片,进入堵塞模式。当睡觉时间结束后,进入就绪状态,等待CPU调度进入就绪状态。

如果参数为0,则表示放弃当前时间片,进入就绪状态。如果参数是INFINITE,则永远进入堵塞状态。

当前线程放弃CPU时间片.

Sleep(0):时间片只能让给优先级相同或更高的线程,MSDN中:A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run.  
SwitchToThread():只要有可调度线程,即便优先级较低,也会让其调度。

线程内核对象

使用次数:2  第一个是内核对象本身,第二个是createThread创建的句柄。使用closehandle关闭句柄会减1,线程执行完毕后减1后使用次数变为0,被操作系统回收。同理,使用openthread也会让引用计数加1.

暂停次数:当调用CreateThread(NULL, NULL, ThreadPro, NULL, CREATE_SUSPENDED, &dwThreadId);或suspendthread会使得暂停次数+1,使用resumeThread会使暂停次数减1.当暂停次数为0时,线程进入就绪状态。

代码:

挂起和恢复线程

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>

DWORD WINAPI ThreadPro(LPVOID lpParam);

int main(void)
{
	HANDLE hThread;
	unsigned int iThreadIdex;
	hThread = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadPro, NULL, 0, &iThreadIdex);
	int count = 0;
	int count2 = 0;
	count = SuspendThread(hThread);
	printf("count = %d\n", count);
	count = SuspendThread(hThread);
	printf("count = %d\n", count);
	count = SuspendThread(hThread);
	printf("count = %d\n", count);
	count = SuspendThread(hThread);
	printf("count = %d\n", count);
	count2 = ResumeThread(hThread);
	printf("count2 = %d\n", count2);
	count2 = ResumeThread(hThread);
	printf("count2 = %d\n", count2);
	count2 = ResumeThread(hThread);
	printf("count2 = %d\n", count2);
	count2 = ResumeThread(hThread);
	printf("count2 = %d\n", count2);
	CloseHandle(hThread);
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro(LPVOID lpParam)
{
	for (int i = 0; i < 2; i++)
	{
		printf("hello\n");
	}
	return 0;
}

sleep和SwitchtoThread

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>

DWORD WINAPI ThreadPro1(LPVOID lpParam);
DWORD WINAPI ThreadPro2(LPVOID lpParam);

int main(void)
{
	HANDLE hThread1;
	unsigned int iThreadIdex1;
	hThread1 = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadPro1, NULL, 0, &iThreadIdex1);
	SetThreadPriority(hThread1, THREAD_PRIORITY_ABOVE_NORMAL);
	CloseHandle(hThread1);

	HANDLE hThread2;
	unsigned int iThreadIdex2;
	hThread2 = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadPro2, NULL, 0, &iThreadIdex2);
	SetThreadPriority(hThread2, THREAD_PRIORITY_BELOW_NORMAL);
	CloseHandle(hThread2);
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro1(LPVOID lpParam)
{
	for (int i = 0; i < 10; i++)
	{
		printf("hello\n");
    Sleep(0);
		//SwitchToThread();
	}
	return 0;
}

DWORD WINAPI ThreadPro2(LPVOID lpParam)
{
	for (int i = 0; i < 10; i++)
	{
		printf("world\n");
		Sleep(0);
		//SwitchToThread();
	}
	return 0;
}

线程1的优先级比线程2的高,sleep(0)后不会考虑调度比自己优先级低的线程2,基本上是先打印hello 再打印world。但是windows操作系统会进行调用,线程2会得到执行的机会

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>

DWORD WINAPI ThreadPro1(LPVOID lpParam);
DWORD WINAPI ThreadPro2(LPVOID lpParam);

int main(void)
{
	HANDLE hThread1;
	unsigned int iThreadIdex1;
	hThread1 = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadPro1, NULL, 0, &iThreadIdex1);
	SetThreadPriority(hThread1, THREAD_PRIORITY_ABOVE_NORMAL);
	CloseHandle(hThread1);

	HANDLE hThread2;
	unsigned int iThreadIdex2;
	hThread2 = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadPro2, NULL, 0, &iThreadIdex2);
	SetThreadPriority(hThread2, THREAD_PRIORITY_BELOW_NORMAL);
	CloseHandle(hThread2);
	system("pause");
	return 0;
}

DWORD WINAPI ThreadPro1(LPVOID lpParam)
{
	for (int i = 0; i < 10; i++)
	{
		printf("hello\n");
		SwitchToThread();
	}
	return 0;
}

DWORD WINAPI ThreadPro2(LPVOID lpParam)
{
	for (int i = 0; i < 10; i++)
	{
		printf("world\n");;
		SwitchToThread();
	}
	return 0;
}

和SHEEP相比,现象并不明显

计时

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>


DWORD WINAPI ThreadPro1(LPVOID)
{
	ULONGLONG ullStart = 0;
	ULONGLONG ullEnd = 0;
	ullStart = GetTickCount64();
	for (int i = 0; i < 100; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			Sleep(10);
			printf("hello world\n");
		}
	}
	ullEnd = GetTickCount64();
	printf("用了%ul毫秒\n", ullEnd - ullStart);
	return 0;
}

int main(int argc, char *argv[])
{
	HANDLE hThread1;
	unsigned int iThreadIdex1;
	hThread1 = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadPro1, NULL, 0, &iThreadIdex1);
	CloseHandle(hThread1);

	system("pause");
	return 0;
}
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>


DWORD WINAPI ThreadPro1(LPVOID)
{
	//ULONGLONG ullStart = 0;
	//ULONGLONG ullEnd = 0;
	//ullStart = GetTickCount64();
	FILETIME ftCreateTime, ftExitTime, ftKernelTimeStart, ftKernelTimeEnd, ftUserTimeStart, ftUserTimeEnd;
	GetThreadTimes(GetCurrentThread(), &ftCreateTime, &ftExitTime, &ftKernelTimeStart, &ftUserTimeStart);
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 100; j++)
		{
			//Sleep(10);
			printf("hello world\n");
		}
	}
	GetThreadTimes(GetCurrentThread(), &ftCreateTime, &ftExitTime, &ftKernelTimeEnd, &ftUserTimeEnd);
	SYSTEMTIME st1,st2;
	FILETIME ftCounter1;
	ftCounter1.dwHighDateTime = ftKernelTimeEnd.dwHighDateTime - ftKernelTimeStart.dwHighDateTime;
	ftCounter1.dwLowDateTime = ftKernelTimeEnd.dwLowDateTime - ftKernelTimeStart.dwLowDateTime;
	FileTimeToSystemTime(&ftCounter1, &st1);
	printf("%d.%d\n", st1.wSecond,st1.wMilliseconds);

	FILETIME ftCounter2;
	ftCounter2.dwHighDateTime = ftUserTimeEnd.dwHighDateTime - ftUserTimeStart.dwHighDateTime;
	ftCounter2.dwLowDateTime = ftUserTimeEnd.dwLowDateTime - ftUserTimeStart.dwLowDateTime;

	FileTimeToSystemTime(&ftCounter2, &st2);
	printf("%d.%d\n", st2.wSecond,st2.wMilliseconds);
	//ullEnd = GetTickCount64();
	//printf("用了%ul毫秒\n", ullEnd - ullStart);
	return 0;
}

int main(int argc, char *argv[])
{
	HANDLE hThread1;
	unsigned int iThreadIdex1;
	hThread1 = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadPro1, NULL, 0, &iThreadIdex1);
	CloseHandle(hThread1);

	system("pause");
	return 0;
}

线程同步

线程执行顺序不对导致问题

非原子操作导致问题:

等待函数:解决执行顺序问题

WaitForSingleObject

WaitForMultipleObjects

主线程等待子线程执行结束后执行:

原子操作:解决代码作为一个单元执行问题

InterLocked

原子操作

 

addend赋值为value

给指针进行原子赋值

比较赋值

位运算赋值:

临界区

临界区工作原理

 

测试是否有锁:

流程:

可能出现的错误:

避免错误:

/*
  线程同步编码实战
  关键段 | 临界区

  CRITICAL_SECTION

  用到的API函数:
  InitializeCriticalSection
  InitializeCriticalSectionAndSpinCount 
  InitializeCriticalSectionEx
  EnterCriticalSection
  TryEnterCriticalSection
  LeaveCriticalSection
  DeleteCriticalSection
 */

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <process.h>

DWORD WINAPI ThreadCounter(LPVOID);

int g_iCount1 = 0;
int g_iCount2 = 0;
int g_iFlag = 1;

CRITICAL_SECTION g_cs;

int main(void)
{
	HANDLE hThread[2];
	unsigned int iThreadIdex;
	//InitializeCriticalSection(&g_cs);
	InitializeCriticalSectionAndSpinCount(&g_cs, 10);
	//InitializeCriticalSectionEx(&g_cs, 10, 0);
	hThread[0] = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadCounter, NULL, 0, &iThreadIdex);
	hThread[1] = (HANDLE)_beginthreadex(NULL, NULL, (_beginthreadex_proc_type)ThreadCounter, NULL, 0, &iThreadIdex);

	Sleep(1000);
	g_iFlag = 0;

	WaitForMultipleObjects(2, hThread, TRUE, INFINITE);

	printf("g_iCount1 = %d\n", g_iCount1);
	printf("g_iCount2 = %d\n", g_iCount2);

	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);

	DeleteCriticalSection(&g_cs);

	system("pause");
	return 0;
}

DWORD WINAPI ThreadCounter(LPVOID lpParameter)
{
	//EnterCriticalSection(&g_cs);
	while(g_iFlag)
	{
		if (TryEnterCriticalSection(&g_cs))
		{
			g_iCount1++; //InterLockedxxxx
			g_iCount2++;
			LeaveCriticalSection(&g_cs);
		}
		else
		{
			printf("hello");
		}
	}
	//LeaveCriticalSection(&g_cs);
	return 0;
}

临界区+条件变量,不需要频繁的试探是否能进入临界区

/*
线程同步编码实战--关键段拓展
关键段 | 临界区  +  条件变量

CRITICAL_SECTION
CONDITION_VARIABLE

条件变量典型使用场合:
生产者 + 消费者  (必须先生产出产品才能消费)

用到的API函数:
InitializeCriticalSection
InitializeCriticalSectionAndSpinCount
InitializeCriticalSectionEx
EnterCriticalSection
TryEnterCriticalSection
LeaveCriticalSection
DeleteCriticalSection

WakeConditionVariable
SleepConditionVariableCS

BOOL SleepConditionVariableCS(
	PCONDITION_VARIABLE ConditionVariable,
	PCRITICAL_SECTION   CriticalSection,
	DWORD               dwMilliseconds
);

VOID WakeConditionVariable(
	PCONDITION_VARIABLE ConditionVariable
);
*/


#include <Windows.h>
#include <process.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
using namespace std;

DWORD WINAPI ReadProc(LPVOID *lparam);
DWORD WINAPI WriteProc(LPVOID *lparam);

DWORD g_iCount = 0;
BOOL g_bFlag = TRUE;
CONDITION_VARIABLE g_cond;   //条件变量

CRITICAL_SECTION g_cs;
vector<int> vct;

int main(void)
{
	InitializeCriticalSectionAndSpinCount(&g_cs, 10);
	HANDLE hThread[2];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)ReadProc, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)WriteProc, NULL, 0, NULL);
	
	Sleep(2000);
	g_bFlag = FALSE;
	WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
	DeleteCriticalSection(&g_cs);
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);

	cout << "g_iCount = " << g_iCount << endl;
	

	system("pause");
	return 0;
}

DWORD WINAPI WriteProc(LPVOID *lparam)
{
	while (g_bFlag)
	{
		EnterCriticalSection(&g_cs);
		vct.push_back(g_iCount);
		g_iCount++;
		cout << "write finished" << endl;
		LeaveCriticalSection(&g_cs);
		
		WakeConditionVariable(&g_cond);
	}
	return 0;
}


DWORD WINAPI ReadProc(LPVOID *lparam)
{
	while (g_bFlag)
	{
		EnterCriticalSection(&g_cs);
		
		while (vct.empty())
		{
			SleepConditionVariableCS(&g_cond, &g_cs, INFINITE);
		}
		cout << vct.back() << endl;
		vct.pop_back();
		cout << "read finished" << endl;

		LeaveCriticalSection(&g_cs);
	}

	return 0;
}

读写锁SRWLOCk

写线程:

读线程:

事件内核对象Event

如果CreateEvent时设置为手动重置,当线程收到事件后要调用ResetEvent将事件状态设置为未触发。如果设置为自动重置,会自动将事件状态由已触发状态设置为未触发状态。

 

#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI Baoshu1(LPVOID *lparam);
DWORD WINAPI Baoshu2(LPVOID *lparam);
DWORD WINAPI Baoshu3(LPVOID *lparam);

HANDLE g_hEvent;

int main(void)
{
  g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//自动重置,初始为未触发

	HANDLE hThread[3];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu3, NULL, 0, NULL);

  printf("main thread\n");
	WaitForMultipleObjects(3, hThread, TRUE, INFINITE);
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);


	system("pause");
	return 0;
}

DWORD WINAPI Baoshu1(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-1\n");
	return 0;
}

DWORD WINAPI Baoshu2(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-2\n");
	return 0;
}

DWORD WINAPI Baoshu3(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-3\n");
	return 0;
}

三个线程都将无限等待

 

#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI Baoshu1(LPVOID *lparam);
DWORD WINAPI Baoshu2(LPVOID *lparam);
DWORD WINAPI Baoshu3(LPVOID *lparam);

HANDLE g_hEvent;

int main(void)
{
  g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//自动重置,初始为未触发

  SetEvent(g_hEvent);//设置为触发状态
	HANDLE hThread[3];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu3, NULL, 0, NULL);

  printf("main thread\n");
	WaitForMultipleObjects(3, hThread, TRUE, INFINITE);
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);


	system("pause");
	return 0;
}

DWORD WINAPI Baoshu1(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-1\n");
	return 0;
}

DWORD WINAPI Baoshu2(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-2\n");
	return 0;
}

DWORD WINAPI Baoshu3(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-3\n");
	return 0;
}

设置为自动重置,setEvent后,只有一个线程会WAIT成功,其他两个线程将无线等待。如果不是设置为自动重置,那么三个线程都会收到事件。



#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI Baoshu1(LPVOID *lparam);
DWORD WINAPI Baoshu2(LPVOID *lparam);
DWORD WINAPI Baoshu3(LPVOID *lparam);

HANDLE g_hEvent;

int main(void)
{
  g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//自动重置,初始为未触发

  SetEvent(g_hEvent);//设置为触发状态
	HANDLE hThread[3];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)Baoshu3, NULL, 0, NULL);

  printf("main thread\n");
	WaitForMultipleObjects(3, hThread, TRUE, INFINITE);
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);


	system("pause");
	return 0;
}

DWORD WINAPI Baoshu1(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-1\n");
  SetEvent(g_hEvent);
	return 0;
}

DWORD WINAPI Baoshu2(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-2\n");
  SetEvent(g_hEvent);
	return 0;
}

DWORD WINAPI Baoshu3(LPVOID *lparam)
{
  WaitForSingleObject(g_hEvent, INFINITE);
  printf("\nthread-3\n");
  SetEvent(g_hEvent);
	return 0;
}

设置为自动重置,当有线程收到事件后,事件自动重置为未触发状态。然后使用setevent重新将事件设置为触发状态,这样三个线程都会收到事件。

可等待计时器WaitableTimer(内核对象)

上面是一个UNION,也就是只能使用三个中的其中一个

 

APC函数在计时器首次触发后调用

启动后5s触发,不重复触发

 

 

代码:

从设置的时间开始,每隔三秒计时器执行一次,计时器自动重置,因此每次只有一个线程能够获取计时器

/*
线程同步:可等待计时器-WaitableTimer
   
   方式一:从指定时间点开始触发计时器
   方式二:从启动开始计时,多长时间后首次触发

   CreateWaitableTimer
   OpenWaitableTimer
   SetWaitableTimer
   CancelWaitableTimer

   WaitForSingleObject   //等待触发状态
*/


#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI BaoShu1(LPVOID *lparam);
DWORD WINAPI BaoShu2(LPVOID *lparam);
DWORD WINAPI BaoShu3(LPVOID *lparam);

HANDLE g_hTimer;

int main(void)
{
  //获取当前时间点
	FILETIME ftLocal;
	FILETIME ftUTC;
	SYSTEMTIME st;
	st.wYear = 2021;
	st.wMonth = 2;
	st.wDayOfWeek = 5;
	st.wDay = 12;
	st.wHour = 19;
	st.wMinute = 52;
	st.wSecond = 59;
	st.wMilliseconds = 0;

	SystemTimeToFileTime(&st, &ftLocal);//当前时间点转local
	LocalFileTimeToFileTime(&ftLocal, &ftUTC);//local转UTC

	LARGE_INTEGER li;//第二个参数
	li.LowPart = ftUTC.dwLowDateTime;
	li.HighPart = ftUTC.dwHighDateTime;

	g_hTimer = CreateWaitableTimer(NULL, FALSE, NULL);//自动重置
	SetWaitableTimer(g_hTimer, &li, 3000, NULL, NULL, FALSE);//3s触发一次

	HANDLE hThread[3];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu3, NULL, 0, NULL);
	WaitForMultipleObjects(3, hThread, TRUE, INFINITE);

	CancelWaitableTimer(g_hTimer);

	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);



	system("pause");
	return 0;
}

DWORD WINAPI BaoShu1(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);

	printf("thread-1\n");


	return 0;
}

DWORD WINAPI BaoShu2(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);
  printf("thread-2\n");

	return 0;
}

DWORD WINAPI BaoShu3(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);
  printf("thread-3\n");

	return 0;
}

 

从启动后开始计时,5秒后触发:

/*
线程同步:可等待计时器-WaitableTimer
   
   方式一:从指定时间点开始触发计时器
   方式二:从启动开始计时,多长时间后首次触发

   CreateWaitableTimer
   OpenWaitableTimer
   SetWaitableTimer
   CancelWaitableTimer

   WaitForSingleObject   //等待触发状态

*/


#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI BaoShu1(LPVOID *lparam);
DWORD WINAPI BaoShu2(LPVOID *lparam);
DWORD WINAPI BaoShu3(LPVOID *lparam);

HANDLE g_hTimer;

int main(void)
{
  //1秒 = 1000毫秒 = 1000 * 1000微秒 = 1000 * 1000 * 1000纳秒
  //注意,必须为有符号数,否则无法形成负数
  const int KOneSecond = 10 * 1000 * 1000;  //以100纳秒为单位的1秒 

  LARGE_INTEGER li;
  //li.LowPart = ftUTC.dwLowDateTime;
  //li.HighPart = ftUTC.dwHighDateTime;
  li.QuadPart = -(5 * KOneSecond);//从启动开始5s
  g_hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
  SetWaitableTimer(g_hTimer, &li, 3000, NULL, NULL, FALSE);//从启动后5秒开始触发,频率是3s

	HANDLE hThread[3];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu3, NULL, 0, NULL);
	WaitForMultipleObjects(3, hThread, TRUE, INFINITE);

	CancelWaitableTimer(g_hTimer);

	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);



	system("pause");
	return 0;
}

DWORD WINAPI BaoShu1(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);

	printf("thread-1\n");


	return 0;
}

DWORD WINAPI BaoShu2(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);
  printf("thread-2\n");

	return 0;
}

DWORD WINAPI BaoShu3(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);
  printf("thread-3\n");

	return 0;
}

 

使用APC函数

/*
线程同步:可等待计时器-WaitableTimer
  
   // 触发APC函数
   SleepEx
   WaitForSingleObjectEx
   WaitForMultipleObjectsEx
   MsgWaitForMultipleObjectsEx
   SignalObjectAndWait

*/


#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI BaoShu1(LPVOID *lparam);
DWORD WINAPI BaoShu2(LPVOID *lparam);
DWORD WINAPI BaoShu3(LPVOID *lparam);

VOID APIENTRY TimerAPCRoutine(PVOID pvArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue);

HANDLE g_hTimer;

int main(void)
{
	const int KOneSecond = 10 * 1000 * 1000;

	LARGE_INTEGER li;
	li.QuadPart = -(5 * KOneSecond);
	g_hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
	//SetWaitableTimer(g_hTimer, &li, 3000, NULL, NULL, FALSE);
	SetWaitableTimer(g_hTimer, &li, 3000, TimerAPCRoutine, NULL, FALSE);

	HANDLE hThread[3];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu3, NULL, 0, NULL);
	//WaitForSingleObjectEx(hThread[0], INFINITE, TRUE);
	//WaitForMultipleObjects(3, hThread, TRUE, INFINITE);
	WaitForMultipleObjectsEx(3, hThread, TRUE, INFINITE, TRUE);//最后一个参数需要设为ture
	//SleepEx(INFINITE, TRUE);
	//WaitForSingleObjectEx(g_hTimer, INFINITE, TRUE);
	//CancelWaitableTimer(g_hTimer);
	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);



	system("pause");
	return 0;
}

DWORD WINAPI BaoShu1(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("1\n");
	}

	return 0;
}

DWORD WINAPI BaoShu2(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("2\n");
	}

	return 0;
}

DWORD WINAPI BaoShu3(LPVOID *lparam)
{
	WaitForSingleObject(g_hTimer, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("3\n");
	}

	return 0;
}

//当首次触发计数器时调用
VOID APIENTRY TimerAPCRoutine(PVOID pvArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
{
	for (int i = 0; i < 10; i++)
		printf("\nhello world\n");
}

信号量semaphore

同时最多只能有两个线程执行;

/*
线程同步: Semaphore   信号量
互斥量使用以下函数

CreateSemaphore
CreateSemaphoreEx
OpenSemaphore
ReleaseSemaphore

WaitForSingleObject   //等待信号量资源
*/
#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI ThreadProc1(LPVOID lpParameter);
DWORD WINAPI ThreadProc2(LPVOID lpParameter);
DWORD WINAPI ThreadProc3(LPVOID lpParameter);
DWORD WINAPI ThreadProc4(LPVOID lpParameter);
DWORD WINAPI ThreadProc5(LPVOID lpParameter);

HANDLE hSemaphore;

int main(void)
{
	hSemaphore = CreateSemaphore(NULL, 2, 2, NULL);
	HANDLE hThread[5];

	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)ThreadProc1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)ThreadProc2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)ThreadProc3, NULL, 0, NULL);
	hThread[3] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)ThreadProc4, NULL, 0, NULL);
	hThread[4] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)ThreadProc5, NULL, 0, NULL);

	WaitForMultipleObjects(5, hThread, TRUE, INFINITE);

	for(int i = 0; i < 5; i++)
	{
		CloseHandle(hThread[i]);
	}

	CloseHandle(hSemaphore);

	system("pause");
	return 0;
}

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
	WaitForSingleObject(hSemaphore, INFINITE);
	printf("\nproc1 start...\n");
	for(int i = 0; i < 3; i++)
	{
		printf("proc1 running...\n");
	}
	printf("\nproc1 end...\n");
	ReleaseSemaphore(hSemaphore, 1, NULL);
	return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
	WaitForSingleObject(hSemaphore, INFINITE);
	printf("\nproc2 start...\n");
	for(int i = 0; i < 3; i++)
	{
		printf("proc2 running...\n");
	}
	printf("\nproc2 end...\n");
	ReleaseSemaphore(hSemaphore, 1, NULL);
	return 0;
}

DWORD WINAPI ThreadProc3(LPVOID lpParameter)
{
	WaitForSingleObject(hSemaphore, INFINITE);
	printf("\nproc3 start...\n");
	for(int i = 0; i < 3; i++)
	{
		printf("proc3 running...\n");
	}
	printf("\nproc3 end...\n");
	ReleaseSemaphore(hSemaphore, 1, NULL);
	return 0;
}

DWORD WINAPI ThreadProc4(LPVOID lpParameter)
{
	WaitForSingleObject(hSemaphore, INFINITE);
	printf("\nproc4 start...\n");
	for(int i = 0; i < 3; i++)
	{
		printf("proc4 running...\n");
	}
	printf("\nproc4 end...\n");
	ReleaseSemaphore(hSemaphore, 1, NULL);
	return 0;
}

DWORD WINAPI ThreadProc5(LPVOID lpParameter)
{
	WaitForSingleObject(hSemaphore, INFINITE);
	printf("\nproc5 start...\n");
	for(int i = 0; i < 3; i++)
	{
		printf("proc5 running...\n");
	}
	printf("\nproc5 end...\n");
	ReleaseSemaphore(hSemaphore, 1, NULL);
	return 0;
}

互斥量MUTEX

 

创建互斥量时,第二个参数指明为false,创建的互斥量并不为当前线程所拥有,所有线程均可以通过waitforsingleobject获取

创建互斥量时,第二个参数指明为TRUE,创建的互斥量并为当前线程所拥有,当前线程不释放互斥量,其他线程通过waitforsingleobject获取不到

某个线程获得互斥量后

系统将互斥量内核对象重置为:

使得互斥量可以继续被使用

 

设置互斥量最初属性:false

/*
  线程同步: mutex   互斥量
  互斥量使用以下函数

  CreateMutex
  CreateMutexEx
  OpenMutex
  ReleaseMutex

  WaitForSingleObject   //等待触发状态
*/

#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI BaoShu1(LPVOID *lparam);
DWORD WINAPI BaoShu2(LPVOID *lparam);
DWORD WINAPI BaoShu3(LPVOID *lparam);

HANDLE g_hMutex;

int main(void)
{
	g_hMutex = CreateMutex(NULL, FALSE, NULL);

	HANDLE hThread[3];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu3, NULL, 0, NULL);
	
	//getchar();
	//ReleaseMutex(g_hMutex);

	WaitForMultipleObjects(3, hThread, TRUE, INFINITE);

	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);



	system("pause");
	return 0;
}

DWORD WINAPI BaoShu1(LPVOID *lparam)
{
	WaitForSingleObject(g_hMutex, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("1\n");
	}

	return 0;
}

DWORD WINAPI BaoShu2(LPVOID *lparam)
{
	WaitForSingleObject(g_hMutex, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("2\n");
	}

	return 0;
}

DWORD WINAPI BaoShu3(LPVOID *lparam)
{
	WaitForSingleObject(g_hMutex, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("3\n");
	}

	return 0;
}

 

设置互斥量最初属性:true,只有当前线程释放互斥量后,创建的三个线程才能去争抢

/*
  线程同步: mutex   互斥量
  互斥量使用以下函数

  CreateMutex
  CreateMutexEx
  OpenMutex
  ReleaseMutex

  WaitForSingleObject   //等待触发状态
*/

#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI BaoShu1(LPVOID *lparam);
DWORD WINAPI BaoShu2(LPVOID *lparam);
DWORD WINAPI BaoShu3(LPVOID *lparam);

HANDLE g_hMutex;

int main(void)
{
	g_hMutex = CreateMutex(NULL, TRUE, NULL);

	HANDLE hThread[3];
	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu1, NULL, 0, NULL);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu2, NULL, 0, NULL);
	hThread[2] = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)BaoShu3, NULL, 0, NULL);
	
	getchar();
	ReleaseMutex(g_hMutex);

	WaitForMultipleObjects(3, hThread, TRUE, INFINITE);

	CloseHandle(hThread[0]);
	CloseHandle(hThread[1]);
	CloseHandle(hThread[2]);



	system("pause");
	return 0;
}

DWORD WINAPI BaoShu1(LPVOID *lparam)
{
	WaitForSingleObject(g_hMutex, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("1\n");
	}

	return 0;
}

DWORD WINAPI BaoShu2(LPVOID *lparam)
{
	WaitForSingleObject(g_hMutex, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("2\n");
	}

	return 0;
}

DWORD WINAPI BaoShu3(LPVOID *lparam)
{
	WaitForSingleObject(g_hMutex, INFINITE);
	for (int i = 0; i < 10; i++)
	{
		printf("3\n");
	}

	return 0;
}

线程同步方式对比

等待子线程完成后执行主线程

/*
  线程同步:SignalObjectAndWait

  第一个参数:互斥量、信号量、事件

  第二个参数:互斥量、信号量、事件、计时器、进程、线程、作业等

 */



#include <Windows.h>
#include <process.h>
#include <stdio.h.>
#include <stdlib.h>

DWORD WINAPI sayhello(LPVOID *lparam);

HANDLE g_hEvent;

int main(void)
{
	g_hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


	HANDLE hThread;
	hThread = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)sayhello, NULL, 0, NULL);
	//SetEvent(g_hEvent);
	//xxx  xxx   xxx
	//WaitForSingleObject(hThread, INFINITE);
	SignalObjectAndWait(g_hEvent, hThread, INFINITE, TRUE);//将上面的两个操作合并为一个原子操作,将事件置为可触发状态,同时等待线程的完成
	for (int i = 0; i < 100; i++)
	{
		printf("world\n");
	}

	CloseHandle(hThread);



	system("pause");
	return 0;
}

DWORD WINAPI sayhello(LPVOID *lparam)
{
	WaitForSingleObject(g_hEvent, INFINITE);
	for (int i = 0; i < 100; i++)
	{
		printf("hello\n");
	}

	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值