进程与线程

1.创建进程API

BOOL CreateProcess(
LPCTSTR lpApplicationName,                       //指向可执行模块的名字,NULL
LPTSTR  lpCommandLine,       					 //传给新进程的命令行字符串,路径
LPSECURITY_ATTRIBUTES lpProcessAttributes, 		 //指定进程的安全属性,NULL
LPSECURITY_ATTRIBUTES lpThreadAttributes,   	 //指定线程的安全属性,NULL
BOOL bInheritHandles,							 //TRUE or FALSE
DWORD dwCreationFlags,							 //进程创建标识,0
LPVOID lpEnvironment,							 //为新进程指定环境字符串,NULL	
LPCTSTR lpcurrentDirectory, 					 //设定子进程的工作目录,NULL
LPSTARTUPINFO lpstartupInfo,					 //指向startupinfo的指针
LPPROCESS_INFORMATION lpProcessInformation	     //指向process_information指针
);

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

WCHAR lpPath[] = L"calc.exe";
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
BOOL bStatus = CreateProcess(NULL,lpPath,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
return 0;

2.创建线程API

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES 1pThreadAttributes,   //线程安全属性,NULL
SIZE_T dwStacksize,                         //新线程的堆栈空间大小
LPTHREAD_START_ROUTINE lpStartAddress       //新线程的函数地址
LPVOID lpParameter,                         //传递给新线程的数据
DWORD dwCreationFlags,						//创建线程的方法
LPDWORD lpThreadId                          //用来接收新线程的ID,若为NULL,不返回线程ID
);
DWORD dwStackSize = 4 * 1024 * 1024;
DWORD dwProcessId = 0;
HANDLE hThread = CreateThread(NULL, dwStackSize, NewThread, NULL, 0, &dwProcessId);

3.使用ToolHelpAPI枚举进程

在这里插入图片描述

#include <iostream>
#include <fstream>
#include <windows.h>
#include <TlHelp32.h>
using namespace std;
#define MAX_BUF_SIZE 100
//枚举系统进程信息存入process.txt
BOOL EnumProcessInfo() {
    //定义进程信息结构
    PROCESSENTRY32 pe32 = { sizeof(pe32) };
    //创建系统当前进程快照
    HANDLE hProcessShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(hProcessShot == INVALID_HANDLE_VALUE)
        return FALSE;
    ofstream fout("process.txt");
    //循环枚举进程信息
    char szBuf[MAX_BUF_SIZE] = { 0 };
    if (Process32First(hProcessShot, &pe32)){
        do {
            memset(szBuf, 0, sizeof(szBuf));
            WideCharToMultiByte(CP_ACP,0,pe32.szExeFile,wcslen(pe32.szExeFile), szBuf, sizeof(szBuf), NULL, NULL);
            fout << "Process:" << szBuf << endl;
            fout << "ProcessID" << pe32.th32ProcessID << endl;
            fout << "ThreadNum" << pe32.cntThreads << endl;
        } while (Process32Next(hProcessShot, &pe32));
    }
    fout.close();
    CloseHandle(hProcessShot);
    return TRUE;
}
//枚举系统线程信息存入thread.txt
BOOL EnumThreadInfo() {
    //定义线程信息结构
    THREADENTRY32 te32 = { sizeof(te32) };
    //创建系统当前线程快照
    HANDLE hThreadShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
    if (hThreadShot == INVALID_HANDLE_VALUE)
        return FALSE;
    ofstream fout("thread.txt");
    //循环枚举线程信息
    if (Thread32First(hThreadShot, &te32)) {
        do {
            fout << "ThreadID:" << te32.th32ThreadID << endl;
            fout << "OwnProcessID" << te32.th32OwnerProcessID << endl;
        } while (Thread32Next(hThreadShot, &te32));
    }
    fout.close();
    CloseHandle(hThreadShot);
    return TRUE;
}
int main() {
    EnumProcessInfo();
    EnumThreadInfo();
    return 0;
}

4.进程间通信

4.1.利用消息机制通信

发送端

HWND hWnd = ::FindWindow ( NULL, L"[第14章]进程间通信之消息通信机制——接收端" ) ;
if ( hWnd )
{
	COPYDATASTRUCT CopyData = {0} ;
	CopyData.dwData = GetCurrentProcessId() ;
	CopyData.cbData = this->szData.GetLength() * 2 + 2 ;
	CopyData.lpData = this->szData.GetBuffer ( CopyData.cbData ) ;
	::SendMessage ( hWnd, WM_COPYDATA, NULL, (LPARAM)&CopyData ) ;
}
else
	this->MessageBox ( L"没有接收端!" ) ;

接收端

BOOL CClientDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
	CString szTempStr ;
	szTempStr.Format ( L"[%d]%s%c%c", pCopyDataStruct->dwData, pCopyDataStruct->lpData, 0xd,0xa ) ;
	this->szData += szTempStr ;
	this->UpdateData ( FALSE ) ;
	return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}

适用于数据量较小的情况下,如果数据量达到1MB以上甚至更多,就不宜使用

4.2.利用共享内存

创建共享内存

HANDLE	hMapFile ;
LPVOID	lpData ;

void CIPC_ShareMemDlg::OnBnClickedCreate()
{	
	if ( this->lpData )
	{
		this->MessageBox ( L"共享内存已经存在!" ) ;
		return ;
	}

	// 创建共享内存
	this->hMapFile = CreateFileMapping ( INVALID_HANDLE_VALUE, \
		NULL,PAGE_READWRITE | SEC_COMMIT,0,DEF_DATA_SIZE,L"ShareMemSample" ) ;
	
	// 映射共享内存
	if ( hMapFile )
		this->lpData = MapViewOfFile ( hMapFile, FILE_MAP_READ|FILE_MAP_WRITE,0,0,0 ) ;

	if ( this->hMapFile == NULL || this->lpData == NULL )
		this->MessageBox ( L"创建共享内存映射文件失败!" ) ;
}

关闭共享内存

void CIPC_ShareMemDlg::OnBnClickedClose()
{
	// 撤消映射的共享内存
	if ( this->lpData )
		UnmapViewOfFile ( this->lpData ) ;

	// 关闭共享内存
	if ( this->hMapFile )
		CloseHandle ( this->hMapFile ) ;
}

写数据到共享内存

void CIPC_ShareMemDlg::OnBnClickedWrite()
{
	if ( this->lpData == NULL )
	{
		this->MessageBox ( L"写入失败!" ) ;
		return ;
	}

	UINT	nLen = this->szData.GetLength()*2+2 ;
	LPWSTR	lpBuf = this->szData.GetBuffer( nLen ) ;

	// 写入共享内存
	memcpy ( this->lpData, (char*)lpBuf, nLen ) ;

	// 检测是否需要通知到客户端
	if ( ((CButton*)this->GetDlgItem(IDC_AUTO_NOTIFY))->GetCheck() == BST_CHECKED )
	{
		HWND hWnd = ::FindWindow ( NULL, L"[第14章]进程间通信之共享内存——读取端" ) ;
		if ( hWnd )
		{
			// 使用自定义消息
			::PostMessage ( hWnd, SHARE_MEM_NOTIFY, 0, 0 ) ;
		}
	}
}

读取数据


void CClientDlg::OnBnClickedRead()
{
	HANDLE hMapFile = OpenFileMapping ( FILE_MAP_READ, FALSE, L"ShareMemSample"); 
	if ( hMapFile == NULL )
	{
		DWORD dwErrorCode = GetLastError () ;
		this->MessageBox ( L"打开共享内存映射文件失败!" ) ;
		return ;
	}

	LPVOID lpBase = MapViewOfFile( hMapFile, FILE_MAP_READ,0,0,0 ) ;
	if ( lpBase == NULL )
	{
		DWORD dwErrorCode = GetLastError () ;
		this->MessageBox ( L"打开共享内存映射文件失败!" ) ;
		return ;
	}

	this->szData.Format ( L"%s", (LPWSTR)lpBase ) ;
	this->UpdateData ( false ) ;

	UnmapViewOfFile ( lpBase ) ;
	CloseHandle ( hMapFile ) ;
}

5.线程同步

5.1.原子操作

互锁系列函数InterlockedExchangeAdd

//函数定义
LONG InterlockedExchangeAdd(
	LONG volatile* Target;   //指向需要修改的整型数据
	LONG Value;				 //需要增加的值
);

5.2.关键代码段

在使用临界对象之前首先需要使用InitiallizeCriticalSection进行初始化

void InitiallizeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

获取访问权限才能使用临界对象执行关键代码段

//会阻塞线程
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
//不会阻塞线程
BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

离开代码段

void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

当不使用临界对象,使用DeleteCriticalSection删除临界对象

void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

实例如下:

#include <windows.h>

#include <iostream>
using namespace std;

#define DEF_DATA_SIZE	1024			// 定义数据大小
#define DEF_THREAD_NUM	30				// 定义线程数量

// 定义共享数据
typedef struct _SHARE_DATA {
	LONG	nCount ;					// 操作次数
	BYTE	data[DEF_DATA_SIZE] ;		// 共享数据主体
} SHARE_DATA ;
SHARE_DATA	ShareData = {0};

// 定义临界区对象
CRITICAL_SECTION cs ;

// 工作线程
DWORD WINAPI WorkThread ( LPVOID lParam )
{
	for ( int i = 0; i < 100; i++ )
	{
		// 进程临界区
		EnterCriticalSection ( &cs ) ;
		// 操作共享数据
		ShareData.nCount ++ ;
		for ( int i = 0; i < DEF_DATA_SIZE; i++ )
			ShareData.data[i] = (BYTE)lParam ;
		// 离开临界区
		LeaveCriticalSection ( &cs ) ;
	}
	return 0 ;
}

int _tmain(int argc, _TCHAR* argv[])
{
	// 初始化临界区对象
	InitializeCriticalSection ( &cs ) ;

	int i = 0 ;
	HANDLE hThread[DEF_THREAD_NUM] = {0} ;
	// 创建多个线程
	for ( i = 0; i < DEF_THREAD_NUM; i++ )
	{
		hThread[i] = CreateThread ( NULL, 0, WorkThread, (LPVOID)i, 0, NULL ) ;
		if ( hThread[i] == NULL )
		{
			cout << "创建线程失败" << endl ;
			break ;
		}
	}

	if ( i == DEF_THREAD_NUM )
	{
		// 等待所有线程结束
		WaitForMultipleObjects ( DEF_THREAD_NUM, hThread, TRUE, INFINITE ) ;
		cout << "count=" << ShareData.nCount << endl ;
	}

	// 关闭所有线程句柄
	for ( i = 0; i < DEF_THREAD_NUM; i++ )
	{
		if ( hThread[i] )
			CloseHandle ( hThread[i] ) ;
	}

	// 删除临界区对象
	DeleteCriticalSection ( &cs ) ;
	return 0;
}

5.3.内核对象与等待函数

一般来说,内核对象有两种状态:已通知状态和未通知状态,状态的切换是由系统为每种对象所建立的一套规则所决定的,当线程或进程结束时,系统就设置该内核对象为已通知状态,同时把等待在内核对象上的线程从阻塞状态转换到就绪状态。

等待函数能够使执行线程进入等待状态,直到其所等待的内核对象变为通知状态为止。

DWORD WaitForSingleObject(
	HANDLE hHandle,           //内核对象句柄
	DWORD  dwMilliseconds  	  //等待超时时间,如果设置为INFINITE即为无超时时间
);
DWORD WaitForMultipleObjects(
	DWORD nCount,              //等待的内核对象数量
	const HANDLE* lpHandles,   //等待的内核对象句柄数组
	BOOL  bWaitAll,            //标识是否等待所有内核对象都变为通知状态才返回
	DWORD dwMilliseconds       //等待超时时间
);

5.4.互斥内核对象

HANDLE CreateMutex(
	LPSECURITY_ATTRIBUTES lpMutexAttributes,  //安全属性,NULL
	BOOL                  bInitialOwner,      //指定对象的初始状态,FALSE
	LPCTSTR               lpName              //对象名称,NULL
);

HANDLE OpenMutex(
	DWORD dwDesiredAccess,  //访问方式
	BOOL  bInheritHandle,   //是否可继承
	LPCTSTR lpName          //对象名称
);

实例

#include <windows.h>

#include <iostream>
using namespace std;

#define DEF_DATA_SIZE	1024			// 定义数据大小
#define DEF_THREAD_NUM	30				// 定义线程数量

// 定义共享数据
typedef struct _SHARE_DATA {
	LONG	nCount ;					// 操作次数
	BYTE	data[DEF_DATA_SIZE] ;		// 共享数据主体
} SHARE_DATA ;
SHARE_DATA	ShareData = {0};

// 定义互斥对象
HANDLE	hMutex = NULL;

// 工作线程
DWORD WINAPI WorkThread ( LPVOID lParam )
{
	for ( int i = 0; i < 100; i++ )
	{
		// 获取互斥对象
		WaitForSingleObject ( hMutex, INFINITE ) ;
		// 操作共享数据
		ShareData.nCount ++ ;
		for ( int i = 0; i < DEF_DATA_SIZE; i++ )
			ShareData.data[i] = (BYTE)lParam ;
		// 释放互斥对象
		ReleaseMutex ( hMutex ) ;
	}
	return 0 ;
}
int _tmain(int argc, _TCHAR* argv[])
{
	// 创建互斥对象
	hMutex = CreateMutex ( NULL, FALSE, NULL ) ;
	if ( hMutex == NULL )
	{
		cout << "创建互斥对象失败!" << endl ;
		return 0 ;
	}

	int i = 0 ;
	HANDLE hThread[DEF_THREAD_NUM] = {0} ;
	// 创建多个线程
	for ( i = 0; i < DEF_THREAD_NUM; i++ )
	{
		hThread[i] = CreateThread ( NULL, 0, WorkThread, (LPVOID)i, 0, NULL ) ;
		if ( hThread[i] == NULL )
		{
			cout << "创建线程失败" << endl ;
			break ;
		}
	}

	if (i == DEF_THREAD_NUM )
	{
		// 等待所有线程结束
		WaitForMultipleObjects ( DEF_THREAD_NUM, hThread, TRUE, INFINITE ) ;
		cout << "count=" << ShareData.nCount << endl ;
	}

	// 关闭所有线程句柄
	for ( i = 0; i < DEF_THREAD_NUM; i++ )
	{
		if ( hThread[i] )
			CloseHandle ( hThread[i] ) ;
	}

	// 删除互斥对象
	CloseHandle ( hMutex ) ;
	return 0;
}

版权声明:本文为qq_43647628原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。