多线程(一)

多线程

基本概念

  • 线程是在进程中产生的一个执行单元,是CPU调度和分配的最小单元,其在同一个进程中与其他线程并行运行,他们可以共享进程内的资源,比如内存、地址空间、打开的文件等待。
  • 进程处于执行期的程序以及它所管理的资源(如打开的文件、挂起的信号、进程状态、地址空间等等)的总称,从操作系统核心角度来说,进程是操作系统调度出CPU时间片外进行的资源分配和保护的进本单位,他有一个独立的虚拟地址空间,用来容纳进程映像(如与进程关联的程序和数据),并以进程为单位对各种资源实施保护,如受保护地方访问处理器、文件、外部设备及其他(进程间通信)
  • 线程是CPU调度和分派的基本单位
  • 进程是分配资源的基本单位

线程创建函数

CreateThread

CreateThread是一种微软在Windows API中提供了建立新的线程的函数,该函数在主线程的基础上创建一个新线程。线程终止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//SD
    //lpThreadAttributes 表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。
SIZE_T dwStackSize,//initialstacksize
    //dwStackSize 表示线程栈空间大小。传入0表示使用默认大小(1MB)。
LPTHREAD_START_ROUTINE lpStartAddress,//threadfunction
    //lpStartAddress 表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。
LPVOID lpParameter,//threadargument
    //lpParameter 是传给线程函数的参数。
DWORD dwCreationFlags,//creationoption
    //dwCreationFlags 指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()。
LPDWORD lpThreadId//threadidentifier
    //lpThreadId 将返回线程的ID号,传入NULL表示不需要返回该线程ID号
)

eg:

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

DWORD WINAPI ThreadFun(LPVOID p)
{
	int iMym = *((int*)p);
	printf("我是子线程,PID = %d,iMym = %d\n", GetCurrentThreadId(), iMym);
	return 0;
}

int main()
{
	printf("main begin\n");

	HANDLE hThread;
	DWORD dwThreadID;
	int m = 100;
	hThread = CreateThread(NULL, 0, ThreadFun, &m, 0, &dwThreadID);
	printf("我是主线程,PID = %d\n", GetCurrentThreadId());
	CloseHandle(hThread);
	Sleep(2000);
	system("pause");
	return 0;
}

_beginthreadex

unsigned long _beginthreadex(
    void *security,    // 安全属性, 为NULL时表示默认安全
    unsigned stack_size,    // 线程的堆栈大小, 一般默认为0
    unsigned(_stdcall *start_address)(void *),   // 线程函数
    void *argilist, // 线程函数的参数
   unsigned initflag,    // 新线程的初始状态,0表示立即执行,//CREATE_SUSPENDED表示创建之后挂起
    unsigned *threaddr    // 用来接收线程ID
);
返回值:成功返回新线程句柄,失败返回0
__stdcall表示
1、参数从右向左压入堆栈
2、函数被调用者修改堆栈

简单多线程示例

1、理解内核对象

​ 定义:内核对象通过API来创建,每个内核对象是一个数据结构,它对应一块内存,由操作系统内核分配,并且只能由操作系统内核访问。在此数据结构中少数成员安全描述符和使用计数是所有对象都有的,但其他大多数成员都是不同类型的对象特有的。内核对象的数据结构只能由操作系统提供的API访问,应用程序在内存中不能访问。调用创建内核对象的函数后,该函数会返回一个句柄,他标识了所创建的对象。它可以由进程的任何线程 使用。

  • CreateProcess
  • CreateThread
  • CreateFile
  • event
  • Job
  • Mutex

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

内核对象:为了管理线程/文件等资源而由操作系统创建的数据块

其创建的所有者肯定是操作系统

第一阶段:主线程和子线程的结束时间

main函数返回后,整个进程终止,同时终止其包含的所有线程。。。

#include  <stdio.h>
#include <windows.h>
#include <process.h>
unsigned WINAPI ThreadFunc(void* arg)
{
	int i;
	int cnt = *((int*)arg);
	for (i = 0; i < cnt; i++)
	{
		Sleep(1000);
		puts("running thread");
	}
	return 0;
}
int main()
{
	printf("main begin\n");
	HANDLE hThread;
	unsigned threadID;
	int iParam = 5;
	hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, 
		(void*)&iParam, 0, &threadID);
	if (hThread == 0)
	{
		puts("_beginthreadex() error");
		return -1;
	}
	Sleep(3000);
	puts("end of main");
	//system("pause");
	return 0;
}

第二阶段

WaitForSingleObject:来等待一个内核对象变为已通知状态

WaitForSingleObject(
	_In_ HANDLE hHandle,	//指明一个内核对象的句柄
    _In_ DWORD dwMilliseconds	//等待时间
);
#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");
	}
	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;
}

第三阶段:

起两个线程,一个加+1,一个减 -1

//Single--Multiple差别
WaitForMultipleObjects(
	_In_ DWORD nCount, //要监测的句柄的组的句柄的个数
    _In_reads_(nCount) CONST HANDLE* lpHandles,	//要监测的句柄的组
    _In_ BOOL bWaitAll, //TRUE等待所有内核对象发出信号,FALSE任意一个内核对象发出信号
    _In_ DWORD dwMilliseconds//等待时间
);
#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;

	printf("sizeof long long: %d\n", sizeof(long long));
	for (int 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 (int i = 0; i < 500000; i++)
		num += 1;
	return 0;
}
unsigned WINAPI threadDes(void* arg)
{
	int i;
	for (int i = 0; i < 500000; i++)
		num -= 1;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值