Windows C++ 内核对象 与多线程 线程同步 互斥对象

Windows C++ 内核对象 与多线程

什么是内核对象:

1.内核对象通过API来创建,每个内核对象是一个数据结构,它对应一块内存,由操作系统内核分 配,并且只能由操作系统内核访问。

2.在此数据结构中少数成员如安全描述符和使用计数是所有对象都有的,但 其他大多数成员都是不同类型的对象特有的。

3.内核对象的数据结构只能由操作系统提供的API访问,应用程 序在内存中不能访问。

4.调用创建内核对象的函数后,该函数会返回一个句柄,它标识了所创建的对象。它可以 由进程的任何线程使用。

5.常见的内核对象:进程、线程、文件,存取符号对象、事件对象、文件对象、作业对象、互斥对象、管道对 象、等待计时器对象,邮件槽对象,信号对象

6.内核对象:为了管理线程/文件等资源而由操作系统创建的数据块。 其创建的所有者肯定是操作系统

对于这一大段话的理解:

1.内核对象是通过API来创立了,特殊的是,他也只能用API来用(位置在内存上)

2.内核对象都有安全描述符和使用计数器

3.内核对象,创立后会返回一个句柄,就是标识这个对象,(重点是,这个进程的所有线程都可以使用)

4.内核对象的创立者是操作系统

还有HANDLE 其实就是一个void* 的指针

typedef void * HANDLE;

仅我个人观点 希望大家给我斧正:我觉得句柄就是标识一个东西。像内核对象这种,他返回一个HANDLE,不就一个指针,标识一个东西嘛。

举个例子:

CreateMutex() 函数:

 HANDLE CreateMutexA(
  [in, optional] LPSECURITY_ATTRIBUTES lpMutexAttributes,
  [in]           BOOL                  bInitialOwner,
  [in, optional] LPCSTR                lpName
);

ReleaseMutex()函数:

public:
 void ReleaseMutex([in] HANDLE mutexName ); // 

你看他创建的时候返回一个 void* 的指针,然后释放地时候,函数内部肯定会用强制转化为Mutex类型的,然后操作,这是我的猜想。我去源代码看看是否正确;查找失败,但我是这么理解的。希望大佬给我指导一哈。

实验一:主线程和子线程的结束时间
#include <stdio.h>
#include <windows.h>
#include <process.h>
unsigned WINAPI ThreadFunc(void* arg);
int main(int argc, char* argv[])
	 {
	HANDLE hThread;
	 unsigned threadID;
	 int param = 5;
	 hThread = (HANDLE)_beginthreadex(NULL, 0, &ThreadFunc, (void*)&param,0, &threadID);
	 if (hThread == 0)
	 {
		 puts("_beginthreadex() error");
		 return-1;
	 }
	 
	 Sleep(3000);
	 puts("end of main");
	 return 0;
 }
 unsigned WINAPI ThreadFunc(void* arg)
 {
	 int i;
	 int cnt = *((int*)arg);
	 for (i = 0; i < cnt; i++)
	 {
		 Sleep(1000); puts("running thread");
	 }
	 puts("子进程结束");
	 return 0;
 }
 
实验一总结:

1.在windows中子进程和主进程是一起走的,在没有设置的情况下。

2.主进程是不会等待子进程的结束后才继续的。

实验二:WaitForSingleObject() 来等待一个内核对象变为已通知状态
#include <stdio.h>
#include <windows.h>
#include <process.h>
unsigned int __stdcall ThreadFun(LPVOID p)
{
	int cnt = *((int*)p);
	for (int i = 0; i < cnt; i++)
	{
		Sleep(1000);
		puts("running thread");
	}
	puts("子线程结束");
	return 0;
}
int main()
{
	printf("main begin\n");
	int iParam = 5;
	unsigned int dwThreadID;
	DWORD wr;
	HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFun,(void*)&iParam, 0, &dwThreadID);
	if (hThread == NULL)
	{
		puts("_beginthreadex() error");
		return-1;
	}
	//
	printf("WaitForSingleObject begin\n");
	if ((wr = WaitForSingleObject(hThread, INFINITE)) == WAIT_FAILED)
	{
		puts("thread wait error");
		return-1;
	}
	printf("WaitForSingleObject end\n");
	printf("main end\n");
	system("pause");
	return 0;
}
DWORD WaitForSingleObject(
  [in] HANDLE hHandle,
  [in] DWORD  dwMilliseconds
);
参数
[in] hHandle

对象的句柄。 有关可以指定其句柄的对象类型的列表,请参阅以下“备注”部分。

如果在等待仍处于挂起状态时关闭此句柄,则函数的行为未定义。

句柄必须具有 SYNCHRONIZE 访问权限。 有关详细信息,请参阅 标准访问权限

[in] dwMilliseconds

超时间隔(以毫秒为单位)。 如果指定了非零值,则函数将等待对象收到信号或经过间隔。 如果 dwMilliseconds 为零,则如果未向对象发出信号,则函数不会进入等待状态;它始终会立即返回。 如果 dwMillisecondsINFINITE,则函数仅在发出对象信号时返回。dwMilliseconds=INFINITE 就是无限期等待,等待到这个内核对象结束,在下面的意思就是等待这个线程结束。

实验二总结:

1.WaitForSingleObject() 函数会等待一个内核对象的变为已通知状态(结束的时候 就是已通知状态)。

2.dwMilliseconds=INFINITE 就是无限期等待

3.hHandle是哪个内核对象的Handle。

实验三:有多个内核对象 并且实现线程同步 通过互斥对象

代码如下:这是错误版的

#include <stdio.h>
#include <windows.h>
#include <process.h>
#define NUM_THREAD 50

unsigned WINAPI threadInc(void* arg);
unsigned WINAPI threadDes(void* arg);
long long num = 0;
int main(int argc, char* argv[])
{
	HANDLE tHandles[NUM_THREAD];
	int i;
	
	for (i = 0; i < NUM_THREAD; i++)
	{
		
		
		if (i % 2)
			tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);
		else
				tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);
	}
	WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);
	printf("result: %lld \n", num);
	return 0;
}
unsigned WINAPI threadInc(void* arg)
{
	int i;
	for (i = 0; i < 500000; i++)
		num += 1;
	return 0;
}

unsigned WINAPI threadDes(void* arg)
{
	int i;
	for (i = 0; i < 500000; i++)
		num -= 1;
	return 0;
}

在多次的实验下发现result一直都不为0,也就是线程没有同步。

WaitForMultipleObjects()
DWORD WaitForMultipleObjects(
  [in] DWORD        nCount,
  [in] const HANDLE *lpHandles,
  [in] BOOL         bWaitAll,
  [in] DWORD        dwMilliseconds
);
参数
[in] nCount

lpHandles 指向的数组中的对象句柄数。 最大对象句柄数 为MAXIMUM_WAIT_OBJECTS。 此参数不能为零。

[in] lpHandles

对象句柄的数组。 有关可以指定其句柄的对象类型的列表。

[in] bWaitAll

如果此参数为 TRUE,则当 发出 lpHandles 数组中所有对象状态的信号时,函数将返回 。 如果 为 FALSE,则当任一对象的状态设置为“已发出信号”时,函数将返回 。 在后一种情况下,返回值指示其状态导致函数返回的对象。

[in] dwMilliseconds

超时间隔(以毫秒为单位)。 如果指定了非零值,则函数将等到指定对象收到信号或间隔已过。 如果 dwMilliseconds 为零,则如果未向指定对象发出信号,则函数不会进入等待状态;它始终立即返回。 如果 dwMillisecondsINFINITE,则仅当指定对象发出信号时,函数才会返回。

CreateMutex()
语法
HANDLE CreateMutex(
  [in, optional] LPSECURITY_ATTRIBUTES lpMutexAttributes,
  [in]           BOOL                  bInitialOwner,
  [in, optional] LPCSTR                lpName
);
参数
[in, optional] lpMutexAttributes

指向 SECURITY_ATTRIBUTES 结构的指针。 如果此参数为 NULL,则子进程无法继承句柄。

[in] bInitialOwner

如果此值为 TRUE 并且调用方创建了互斥体,则调用线程获取互斥对象的初始所有权。 否则,调用线程不会获得互斥体的所有权。

[in, optional] lpName

互斥对象的名称。 名称限制为 MAX_PATH 个字符。 名称比较区分大小写。

返回值

如果函数成功,则返回值是新创建的互斥对象的句柄。

如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。

void ReleaseMutex()
public:
 void ReleaseMutex();

释放互斥对象

代码如下:正确版

#include <stdio.h>
#include <windows.h>
#include <process.h>
#define NUM_THREAD 50

unsigned WINAPI threadInc(void* arg);
unsigned WINAPI threadDes(void* arg);
long long num = 0;
HANDLE hMutex = NULL;
int main(int argc, char* argv[])
{
	HANDLE tHandles[NUM_THREAD];
	int i;
	hMutex = CreateMutex(NULL, FALSE, NULL);

	for (i = 0; i < NUM_THREAD; i++)
	{
		
		
		if (i % 2)
			tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);
		else
				tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);
	}
	WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);
	printf("result: %lld \n", num);
	return 0;
}
unsigned WINAPI threadInc(void* arg)
{
	int i;
	
	for (i = 0; i < 500000; i++)
		num += 1;
	ReleaseMutex(hMutex);
	return 0;
}

unsigned WINAPI threadDes(void* arg)
{
	int i;
	WaitForSingleObject(hMutex, INFINITE);
	for (i = 0; i < 500000; i++)
		num -= 1;
	ReleaseMutex(hMutex);
	return 0;
}

实验三总结:

1.用了互斥对象后 我们在子线程的代码中 加入WaitForSingleObject(hMutex, INFINITE); 我的理解就是,看hMutex有没有线程用,没有的话,就占用;

2.ReleaseMutex(hMutex); 释放占用的句柄hMutex;

3.CreateMutex(NULL, FALSE, NULL);创建了互斥对象,初始是没有被占用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值