首页 > 其他分享 >滴水逆向笔记系列-win32总结5-52.临界区-53.互斥体

滴水逆向笔记系列-win32总结5-52.临界区-53.互斥体

时间:2024-03-16 23:34:53浏览次数:23  
标签:10 dwInt szBuffer 52 win32 互斥 线程 szBuffer1 NULL

第五十二课 win32 临界区

1.线程安全问题

其实就是多个线程同时对一个资源(即全局变量等)进行操作
image.png

2.临界区

设计图

image.png

临界区的使用

1、创建CRITICAL_SECTION:					
					
CRITICAL_SECTION cs;					
					
2、在使用前进行初始化					
					
InitializeCriticalSection(&cs);					
					
					
3、在函数中使用:					
					
DWORD WINAPI 线程A(PVOID pvParam) 					
{					
      EnterCriticalSection(&cs);					
					
      //对全局遍历X的操作					
					
      LeaveCriticalSection(&cs);					
   return(0);					
}					
					
					
DWORD WINAPI 线程B(PVOID pvParam) 					
{					
      EnterCriticalSection(&g_cs);					
					
      //对全局遍历X的操作					
					
      LeaveCriticalSection(&g_cs);					
   return(0);					
}					
					
4、删除CRITICAL_SECTION					
					
VOID DeleteCriticalSection(PCRITICAL_SECTION pcs);					
					
当线程不再试图访问共享资源时					

CRITICAL_SECTION

typedef struct _RTL_CRITICAL_SECTION {		
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;		
    LONG LockCount;		
    LONG RecursionCount;		
    HANDLE OwningThread;       		
    HANDLE LockSemaphore;		
    DWORD SpinCount;		
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;		

:::info
LockCount:
它被初始化为数值 -1
此数值等于或大于 0 时,表示此临界区被占用
等待获得临界区的线程数:LockCount - (RecursionCount -1)
RecursionCount:
此字段包含所有者线程已经获得该临界区的次数
OwningThread:
此字段包含当前占用此临界区的线程的线程标识符
此线程 ID 与GetCurrentThreadId 所返回的 ID 相同
:::

测试代码

#include "stdafx.h"		
#include <windows.h>		
CRITICAL_SECTION cs;		
		
DWORD WINAPI ThreadProc1(LPVOID lpParameter)		
{		
	for(int x=0;x<1000;x++)	
	{	
		  EnterCriticalSection(&cs);
		  
		  Sleep(1000);
		
		  printf("11111:%x %x %x\n",cs.LockCount,cs.RecursionCount,cs.OwningThread);
		  
		  LeaveCriticalSection(&cs);
		
	}	
	return 0;	
}		
		
DWORD WINAPI ThreadProc2(LPVOID lpParameter)		
{		
	for(int x=0;x<1000;x++)	
	{	
		EnterCriticalSection(&cs);
		
		Sleep(1000);
		
		printf("22222:%x %x %x\n",cs.LockCount,cs.RecursionCount,cs.OwningThread);
		
		LeaveCriticalSection(&cs);
		
	}	
		
	return 0;	
}		
		
DWORD WINAPI ThreadProc3(LPVOID lpParameter)		
{		
	for(int x=0;x<1000;x++)	
	{	
		EnterCriticalSection(&cs);
		
		Sleep(1000);
		
		printf("33333:%x %x %x\n",cs.LockCount,cs.RecursionCount,cs.OwningThread);
		
		LeaveCriticalSection(&cs);
		
	}	
		
	return 0;	
}		
		
DWORD WINAPI ThreadProc4(LPVOID lpParameter)		
{		
	for(int x=0;x<1000;x++)	
	{	
		EnterCriticalSection(&cs);
		
		Sleep(1000);
		
		printf("44444:%x %x %x\n",cs.LockCount,cs.RecursionCount,cs.OwningThread);
		
		LeaveCriticalSection(&cs);
		
	}	
		
	return 0;	
}		
		
		
int main(int argc, char* argv[])		
{		
	InitializeCriticalSection(&cs);	
		
	//printf("主线程:%x %x %x\n",cs.LockCount,cs.RecursionCount,cs.OwningThread);	
		
	//创建一个新的线程	
	HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1, 	
		NULL, 0, NULL);
		
	//创建一个新的线程	
	HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2, 	
		NULL, 0, NULL);
		
	//创建一个新的线程	
	HANDLE hThread3 = ::CreateThread(NULL, 0, ThreadProc3, 	
		NULL, 0, NULL);
		
	//创建一个新的线程	
	HANDLE hThread4 = ::CreateThread(NULL, 0, ThreadProc4, 	
		NULL, 0, NULL);
		
	//如果不在其他的地方引用它 关闭句柄	
	::CloseHandle(hThread1);	
	::CloseHandle(hThread2);	
	::CloseHandle(hThread3);	
	::CloseHandle(hThread4);	
		
	Sleep(1000*60*60);	
		
	return 0;	
}		

image.png3-(1-1)=3,还有三个线程在等待临界区

3.合理使用临界区

问题一:
image.pngimage.pngimage.png
令牌操作应该紧贴对变量的操作,应该把令牌操作放进循环里,不然程序则变成单线程,只有那个函数执行完释放令牌,下一个函数才能执行

4.单独锁

问题场景
image.png
解决方法:单独锁
image.png

作业

写一个死锁程序

#include <windows.h>
#include <iostream>

CRITICAL_SECTION cs1;
CRITICAL_SECTION cs2;

DWORD WINAPI ThreadProc1(LPVOID lpParam) {
    EnterCriticalSection(&cs1);
    cout << "Thread 1 acquired Critical Section 1" << endl;

    Sleep(1000);

    EnterCriticalSection(&cs2);
    cout << "Thread 1 acquired Critical Section 2" << endl;

    LeaveCriticalSection(&cs2);
    cout << "Thread 1 released Critical Section 2" << endl;

    LeaveCriticalSection(&cs1);
    cout << "Thread 1 released Critical Section 1" << endl;

    return 0;
}

DWORD WINAPI ThreadProc2(LPVOID lpParam) {
    EnterCriticalSection(&cs2);
    cout << "Thread 2 acquired Critical Section 2" << endl;

    Sleep(1000);

    EnterCriticalSection(&cs1);
    cout << "Thread 2 acquired Critical Section 1" << endl;

    LeaveCriticalSection(&cs1);
    cout << "Thread 2 released Critical Section 1" << endl;

    LeaveCriticalSection(&cs2);
    cout << "Thread 2 released Critical Section 2" << endl;

    return 0;
}

int main() {
    InitializeCriticalSection(&cs1);
    InitializeCriticalSection(&cs2);

    HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
    HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
}

第五十三课 win32 互斥体

感觉和下一节课事件对象一起理解会更好理解互斥体的本质
所有线程都是读取资源而没有写入操作是不需要互斥的,且只有一个线程去写入也是不需要互斥
需要互斥的情况是:多个线程写入同一个资源或者同一个资源被多个线程读取和写入

1.WaitForSingleObject函数

个人理解:比如在线程中创建线程尤为重要,使用了的话他会线程会等待里面的线程执行完后再释放本线程,否则就会出现本线程已释放但是里面的线程还在执行的情况,具体代码参考作业

DWORD WaitForSingleObject(					
  HANDLE hHandle,        // handle to object					
  DWORD dwMilliseconds   // time-out interval					
);					

功能说明:
等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变已通知状态为止.
hHandle:
内核对象句柄,可以是进程也可以是线程.
dwMilliseconds:
等待时间,单位是毫秒 。值为**INFINITE(-1)**一直等待,超过等待时间则直接执行下面代码并返回值为102超时
返回值:
WAIT_OBJECT_0(0) 等待对象变为已通知
WAIT_TIMEOUT(0x102) 超时

特别说明:
1、内核对象中的每种对象都可以说是处于已通知或未通知的状态之中
2、这种状态的切换是由Microsoft为每个对象建立的一套规则来决定的(相当于有一个循环函数一直在读这个句柄的状态结构体的一个参数,直到他变成已通知)
3、当线程正在运行的时候,线程内核对象处于未通知状态,当线程终止运行的时候,它就变为已通知状态
5、在内核中就是个BOOL值,运行时FALSE 结束TRUE
6、下面代码情况时需注意内核对象句柄可能在函数执行后又会把状态改成未通知,虽然线程和进程这种内核对象不会但是不能保证其他内核对象不会这样
image.png

示例代码

DWORD WINAPI ThreadProc1(LPVOID lpParameter)					
{					
	for(int i=0;i<5;i++)				
	{				
		printf("+++++++++\n");			
		Sleep(1000);			
	}				
	return 0;				
}					
					
int main(int argc, char* argv[])					
{					
					
	//创建一个新的线程				
	HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1, 				
		NULL, 0, NULL);			
					
	DWORD dwCode = ::WaitForSingleObject(hThread1, INFINITE);				
					
	MessageBox(0,0,0,0);				
					
	return 0;				
}						

2.WaitForMultipleObjects函数

DWORD WaitForMultipleObjects(						
  DWORD nCount,             // number of handles in array						
  CONST HANDLE *lpHandles,  // object-handle array						
  BOOL bWaitAll,            // wait option						
  DWORD dwMilliseconds      // time-out interval						
);

功能说明:
同时查看若干个内核对象的已通知状态
nCount:
要查看内核对象的数量
lpHandles:
内核对象数组
bWaitAll:
等到类型 TRUE 等到所有变为已通知 FALSE 只要有一个变为已通知
dwMilliseconds:
超时时间 ;INFINITE一直等待
返回值:
bWaitAll为TRUE时,返回WAIT_OBJECT_0(0) 代码所以内核对象都变成已通知
bWaitAll为FALSE时,返回最先变成已通知的内核对象在数组中的索引
WAIT_TIMEOUT(0x102) 超时

示例代码

int main(int argc, char* argv[])							
{							
							
	HANDLE hArray[2];						
							
	//创建一个新的线程						
	HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1, 						
		NULL, 0, NULL);					
							
	//创建一个新的线程						
	HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2, 						
		NULL, 0, NULL);					
							
	hArray[0] = hThread1;						
	hArray[1] = hThread2;						
							
	DWORD dwCode = ::WaitForMultipleObjects(2, hArray,FALSE,INFINITE);						
							
	MessageBox(0,0,0,0);						
							
	return 0;						
}

3.跨进程的线程控制之于互斥体

示例代码

进程一:
HANDLE g_hMutex = CreateMutex(NULL,FALSE, "XYZ");
进程二:
HANDLE g_hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");
WaitForSingleObject(g_hMutex,INFINITE);
//逻辑代码
ReleaseMutex(g_hMutex);
进程三:
HANDLE g_hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");
WaitForSingleObject(g_hMutex,INFINITE);
//逻辑代码
ReleaseMutex(g_hMutex);

互斥体与临界区的区别:

1、临界区只能用于单个进程间的线程控制.
2、互斥体可以设定等待超时(WaitForSingleObject第二个参数),但临界区不能.
3、线程意外终结时,Mutex可以避免无限等待.
4、Mutex效率没有临界区高.
5、互斥体是内核对象,临界区是非内核对象

作业(临界区和互斥体)

image.png
注意所有界面操作比如编辑框里面的数自加1,都需要另起线程去操作而不是在主线程中操作

使用临界区

#include <Windows.h>
#include <stdio.h>
#include "resource.h"
#pragma warning(disable:4996)


HWND hEdit1;
HWND hEdit2;
HWND hEdit3;
HWND hEdit4;
CRITICAL_SECTION cs;
BOOL flag = TRUE;;

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
	TCHAR szBuffer[10];
	TCHAR szBuffer1[10];
	DWORD dwInt;
	DWORD dwInt1;
	memset(szBuffer, 0, 10);
	memset(szBuffer1, 0, 10);
	while (flag)
	{
		
		EnterCriticalSection(&cs);
		
		GetWindowText(hEdit1, szBuffer, 10);
		GetWindowText(hEdit2, szBuffer1, 10);
		sscanf(szBuffer, "%d", &dwInt);
		sscanf(szBuffer1, "%d", &dwInt1);
		dwInt = dwInt - 50;
		dwInt1 = dwInt1 + 50;
		
		sprintf(szBuffer, "%d", dwInt);
		sprintf(szBuffer1, "%d", dwInt1);
		SetWindowText(hEdit1, szBuffer);
		SetWindowText(hEdit2, szBuffer1);
		if (dwInt == 0)
		{
			flag = false;
		}
		LeaveCriticalSection(&cs);
		
		Sleep(500);
	}
	return 2;
	
}
DWORD WINAPI ThreadProc3(LPVOID lpParameter)
{
	TCHAR szBuffer[10];
	TCHAR szBuffer1[10];
	DWORD dwInt;
	DWORD dwInt1;
	memset(szBuffer, 0, 10);
	memset(szBuffer1, 0, 10);
	while (flag)
	{
		
		EnterCriticalSection(&cs);
		GetWindowText(hEdit1, szBuffer, 10);
		GetWindowText(hEdit3, szBuffer1, 10);
		sscanf(szBuffer, "%d", &dwInt);
		sscanf(szBuffer1, "%d", &dwInt1);
		dwInt = dwInt - 50;
		dwInt1 = dwInt1 + 50;
		
		sprintf(szBuffer, "%d", dwInt);
		sprintf(szBuffer1, "%d", dwInt1);
		SetWindowText(hEdit1, szBuffer);
		SetWindowText(hEdit3, szBuffer1);
		if (dwInt == 0)
		{
			flag = false;
		}
		LeaveCriticalSection(&cs);
		Sleep(500);
	}

	return 3;
}
DWORD WINAPI ThreadProc4(LPVOID lpParameter)
{
	TCHAR szBuffer[10];
	TCHAR szBuffer1[10];
	DWORD dwInt;
	DWORD dwInt1;
	memset(szBuffer, 0, 10);
	memset(szBuffer1, 0, 10);
	while (flag)
	{
		
		EnterCriticalSection(&cs);
		
		GetWindowText(hEdit1, szBuffer, 10);
		GetWindowText(hEdit4, szBuffer1, 10);
		sscanf(szBuffer, "%d", &dwInt);
		sscanf(szBuffer1, "%d", &dwInt1);
		dwInt = dwInt - 50;
		dwInt1 = dwInt1 + 50;
		
		sprintf(szBuffer, "%d", dwInt);
		sprintf(szBuffer1, "%d", dwInt1);
		SetWindowText(hEdit1, szBuffer);
		SetWindowText(hEdit4, szBuffer1);
		if (dwInt == 0)
		{
			flag = false;
		}
		LeaveCriticalSection(&cs);
		
		Sleep(500);
	}

	return 4;
}

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
	InitializeCriticalSection(&cs);
	HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
	HANDLE hThread3 = ::CreateThread(NULL, 0, ThreadProc3, NULL, 0, NULL);
	HANDLE hThread4 = ::CreateThread(NULL, 0, ThreadProc4, NULL, 0, NULL);
	WaitForSingleObject(hThread2, INFINITE);
	WaitForSingleObject(hThread3, INFINITE);
	WaitForSingleObject(hThread4, INFINITE);
	CloseHandle(hThread2);
	CloseHandle(hThread3);
	CloseHandle(hThread4);
	DeleteCriticalSection(&cs);
	return 1;
}

BOOL CALLBACK DialogProc(
	HWND hwndDlg,  // handle to dialog box			
	UINT uMsg,     // message			
	WPARAM wParam, // first message parameter			
	LPARAM lParam  // second message parameter			
)
{

	switch (uMsg)
	{
	case  WM_INITDIALOG:
	{
		hEdit1 = GetDlgItem(hwndDlg, IDC_EDIT1);
		SetWindowText(hEdit1,TEXT("0"));

		hEdit2 = GetDlgItem(hwndDlg, IDC_EDIT2);
		SetWindowText(hEdit2, TEXT("0"));

		hEdit3 = GetDlgItem(hwndDlg, IDC_EDIT3);
		SetWindowText(hEdit3, TEXT("0"));

		hEdit4 = GetDlgItem(hwndDlg, IDC_EDIT4);
		SetWindowText(hEdit4, TEXT("0"));
		

		return TRUE;
	}
	case  WM_CLOSE:

		EndDialog(hwndDlg, 0);

		return TRUE;

	case  WM_COMMAND:

		switch (LOWORD(wParam))
		{
		case   IDC_BUTTON1:

			HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
			
			//::CloseHandle(hThread1);
			return TRUE;

		}
		break;
	}
	return FALSE;
}

int CALLBACK WinMain(
	_In_  HINSTANCE hInstance,
	_In_  HINSTANCE hPrevInstance,
	_In_  LPSTR lpCmdLine,
	_In_  int nCmdShow
)
{
	
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);
	
	return 0;
}

使用互斥体

#include <Windows.h>
#include <stdio.h>
#include "resource.h"
#pragma warning(disable:4996)


HWND hEdit1;
HWND hEdit2;
HWND hEdit3;
HWND hEdit4;
HANDLE g_hMutex;
BOOL flag = TRUE;;

DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
	TCHAR szBuffer[10];
	TCHAR szBuffer1[10];
	DWORD dwInt;
	DWORD dwInt1;
	memset(szBuffer, 0, 10);
	memset(szBuffer1, 0, 10);
	while (flag)
	{
		
		WaitForSingleObject(g_hMutex, INFINITE);
		
		GetWindowText(hEdit1, szBuffer, 10);
		GetWindowText(hEdit2, szBuffer1, 10);
		sscanf(szBuffer, "%d", &dwInt);
		sscanf(szBuffer1, "%d", &dwInt1);
		dwInt = dwInt - 50;
		dwInt1 = dwInt1 + 50;
		
		sprintf(szBuffer, "%d", dwInt);
		sprintf(szBuffer1, "%d", dwInt1);
		SetWindowText(hEdit1, szBuffer);
		SetWindowText(hEdit2, szBuffer1);
		if (dwInt == 0)
		{
			flag = false;
		}
		ReleaseMutex(g_hMutex);
		
		Sleep(500);
	}
	return 2;
	
}
DWORD WINAPI ThreadProc3(LPVOID lpParameter)
{
	TCHAR szBuffer[10];
	TCHAR szBuffer1[10];
	DWORD dwInt;
	DWORD dwInt1;
	memset(szBuffer, 0, 10);
	memset(szBuffer1, 0, 10);
	while (flag)
	{
		
		WaitForSingleObject(g_hMutex, INFINITE);
		GetWindowText(hEdit1, szBuffer, 10);
		GetWindowText(hEdit3, szBuffer1, 10);
		sscanf(szBuffer, "%d", &dwInt);
		sscanf(szBuffer1, "%d", &dwInt1);
		dwInt = dwInt - 50;
		dwInt1 = dwInt1 + 50;
		
		sprintf(szBuffer, "%d", dwInt);
		sprintf(szBuffer1, "%d", dwInt1);
		SetWindowText(hEdit1, szBuffer);
		SetWindowText(hEdit3, szBuffer1);
		if (dwInt == 0)
		{
			flag = false;
		}
		ReleaseMutex(g_hMutex);
		Sleep(500);
	}

	return 3;
}
DWORD WINAPI ThreadProc4(LPVOID lpParameter)
{
	TCHAR szBuffer[10];
	TCHAR szBuffer1[10];
	DWORD dwInt;
	DWORD dwInt1;
	memset(szBuffer, 0, 10);
	memset(szBuffer1, 0, 10);
	while (flag)
	{
		
		WaitForSingleObject(g_hMutex, INFINITE);
		GetWindowText(hEdit1, szBuffer, 10);
		GetWindowText(hEdit4, szBuffer1, 10);
		sscanf(szBuffer, "%d", &dwInt);
		sscanf(szBuffer1, "%d", &dwInt1);
		dwInt = dwInt - 50;
		dwInt1 = dwInt1 + 50;
		
		sprintf(szBuffer, "%d", dwInt);
		sprintf(szBuffer1, "%d", dwInt1);
		SetWindowText(hEdit1, szBuffer);
		SetWindowText(hEdit4, szBuffer1);
		if (dwInt == 0)
		{
			flag = false;
		}
		ReleaseMutex(g_hMutex);
		
		Sleep(500);
	}

	return 4;
}

DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
	g_hMutex = CreateMutex(NULL, FALSE, "XYZ");
	HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
	HANDLE hThread3 = ::CreateThread(NULL, 0, ThreadProc3, NULL, 0, NULL);
	HANDLE hThread4 = ::CreateThread(NULL, 0, ThreadProc4, NULL, 0, NULL);
	WaitForSingleObject(hThread2, INFINITE);
	WaitForSingleObject(hThread3, INFINITE);
	WaitForSingleObject(hThread4, INFINITE);
	CloseHandle(hThread2);
	CloseHandle(hThread3);
	CloseHandle(hThread4);
	return 1;
}

BOOL CALLBACK DialogProc(
	HWND hwndDlg,  // handle to dialog box			
	UINT uMsg,     // message			
	WPARAM wParam, // first message parameter			
	LPARAM lParam  // second message parameter			
)
{

	switch (uMsg)
	{
	case  WM_INITDIALOG:
	{
		hEdit1 = GetDlgItem(hwndDlg, IDC_EDIT1);
		SetWindowText(hEdit1,TEXT("0"));

		hEdit2 = GetDlgItem(hwndDlg, IDC_EDIT2);
		SetWindowText(hEdit2, TEXT("0"));

		hEdit3 = GetDlgItem(hwndDlg, IDC_EDIT3);
		SetWindowText(hEdit3, TEXT("0"));

		hEdit4 = GetDlgItem(hwndDlg, IDC_EDIT4);
		SetWindowText(hEdit4, TEXT("0"));
		

		return TRUE;
	}
	case  WM_CLOSE:

		EndDialog(hwndDlg, 0);

		return TRUE;

	case  WM_COMMAND:

		switch (LOWORD(wParam))
		{
		case   IDC_BUTTON1:

			HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
			
			//::CloseHandle(hThread1);
			return TRUE;

		}
		break;
	}
	return FALSE;
}

int CALLBACK WinMain(
	_In_  HINSTANCE hInstance,
	_In_  HINSTANCE hPrevInstance,
	_In_  LPSTR lpCmdLine,
	_In_  int nCmdShow
)
{
	
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);
	
	return 0;
}

问题:
1、为什么调试代码时执行SetWindowText(hEdit4, szBuffer1);后不会实时写入编辑框
image.png
2、之前编辑框1自减到负数还会一直无限自减,后面发现是flag应该设置成全局变量
3、我发现sleep要写久一点,按作业要求sleep(50)的话结果老是会多出100,因为在线程切换的20ms的间隙其他两个线程如果已经进入了循环,那么在红包总量剩0的时候,就算flag已经修改成false,但是其他两个线程的循环还是会执行完,也就会各自多出50

4、调试多线程

的时候要在各个线程都下个断点才好调试,这次是第一次调试多线程整了我老半天

标签:10,dwInt,szBuffer,52,win32,互斥,线程,szBuffer1,NULL
From: https://www.cnblogs.com/xiaoxin07/p/18077884

相关文章

  • 滴水逆向笔记系列-win32总结1-43.宽字节-44.事件_消息_消息处理函数
    第四十三课win32宽字节1.编码0x00.ASCII码1、ASCII码使用指定的7位或8位二进制数组合来表示128或256种可能的字符2、标准ASCII码使用7位二进制数来表示所有的大写和小写字母,数字0到9、标点符号,以及在美式英语中使用的特殊控制字符。3、扩展ASCII码允许将......
  • 滴水逆向笔记系列-win32总结2-45.esp寻址_定位回调函数-46.子窗口_消息处理函数-47.资
    第四十五课win32esp寻址_定位回调函数自己vs编译的exe入口函数好像和课程视频哩的vc6不一样,没办法跟着视频走,可以用课件里给的作业exe勉强跟着视频学,前面的都差不多,课件下载地址:https://www.bcdaren.com/video/videoPlay/3303185150621818881.win32应用程序入口识别没加过壳......
  • 滴水逆向笔记系列-win32总结3-48.提取图标_修改标题-49.通用控件_实现LoadPE
    第四十八课win32提取图标_修改标题1.添加图标a,.右键添加icon时不要直接新建,导入b.加载图标:::infoHICONhIcon;hIcon=LoadIcon(hAppInstance,MAKEINTRESOURCE(IDI_ICON));hAppInstance 应用程序句柄IDI_ICON 图标编号MAKEINTRESOURCE 用这个宏的主要原因......
  • Linux第79步_使用自旋锁保护某个全局变量来实现“互斥访问”共享资源
    自旋锁使用注意事项:自旋锁保护的“临界区”要尽可能的短。因此,在open()函数中申请“spinlock_t自旋锁结构变量”,然后在release()函数中释放“spinlock_t自旋锁结构变量”,这种方法就行不通了。如果使用一个变量“dev_stats”来表示“共享资源的使用标志”,则“dev_stats>0”,......
  • RC522刷卡电路设计及程序
    一、RC522刷卡电路组成基于RC522的刷卡电路如上图所示。该电路组成主要分为三部分:ReceivingCircuit:接收电路,接收卡发送的数据。FilteringImpedence-Transtormcircuit:滤波和阻抗变换电路,抑制高次谐波并优化到读卡器天线的功率传输。MatchingCircuit:天线匹配电路。......
  • Vue学习笔记52--全局事件总线
    Vue全局事件总线:一种组件之间通信的方式,适用于任意组件之间通信。1.所有组件,即VueComponent所有的组件实例对象vc2.每次使用VueComponent都是new一个新的vc3.Vue.prototype=VueComponent.prototype.__proto__(可以让组件实例对象vc访问到Vue原型上的属性、方法)4.$emit、$o......
  • 【Linux】互斥 | 死锁
    线程互斥一些概念临界资源:多线程之间共享的资源就是临界资源。通常为一些全局的变量。临界区:访问或者修改临界资源的代码就是临界区。互斥:任何时刻,保证只有一个执行流访问临界资源。原子性:不受调度机制打断的操作。操作要么完成,要么就是未完成,一步到位。锁的背景编写一个......
  • python下载win32gui的库失败解决教程
    1、进入这个网站https://www.lfd.uci.edu/~gohlke/pythonlibs/界面如下:因为这些安装包都是按照字母顺序排序的,所以就向下翻到pywin32的位置就行;选择跟自己的python版本相对应的这个库的版本,点击即可下载;等待下载完成:2、进入到pycharm软件里面,运用命令实现库的安装python-......
  • 并发支持库:互斥锁及其管理
    目录互斥std::mutex(c++11)std::timed_mutex(c++11)std::recursive_mutex(c++11)std::recursive_timed_mutex(c++11)std::shared_mutex(c++17)shared_timed_mutex(C++14)通用互斥(mutex)管理std::lock_guard(c++11)std::scoped_lock(c++17)std::unique_lock(C++11)std::shared_loc......
  • pywin32:批量将doc文件转为docx
    学习自:python批量把doc文件转换成docx_python批量将doc转docx-CSDN博客目的:将某个目录下(包括子目录)中的所有doc转为docximportosimportdocximportwin32com.clientaswin32url='D:\规范文档'word=win32.Dispatch('Word.Application')forroot,dir2,filesinos.walk(u......