设为首页 加入收藏

TOP

Win32学习3(一)
2023-07-23 13:25:10 】 浏览:53
Tags:Win32 学习

9、创建线程

①什么是线程?

<1>线程是附属在进程上的执行实体,是代码的执行流程。 <2> 一个进程可以包含多个线程,但一个进程至少要包含一个线程。

可以这么理解,进程属于是空间上的概念,是代表了4GB 的虚拟内存,而线程属于是时间上的概念,也就是说线程也就是当前正在运行中的实际的代码。在任务管理器中可以看到,一个进程包含数个线程,也就是当前这个进程有数段代码正在执行。(但不一定都是同时执行) 举个例子,当前电脑中是单个单核CPU,它也是可以执行同时执行多个线程的。在单核CPU上运行多线程并非真正意义上的多线程。我们可以这么理解,在某个时间点上,只能有一段代码在执行。但CPU执行的效率特别高,切换的比较快,这会执行的A线程,这一会执行的B线程,就仿佛两段代码在同时跑。单核的情况下是不存在多线程的。在某一个时间点上只能有一段代码在执行。一个CPU核只有一套寄存器,一套寄存器必定不能同时执行多个不同的代码。

总结上可以这么理解,一个单核CPU执行代码,多线程实际上是分时段的,这个时间段执行这段代码,另一个时间段执行另一段代码。但是无论是单核还是多核,给我们的感觉都好像是多个线程同时在跑。

②创建线程

HANDLE CreateThread(
LPSECURITY_ATTRIBUTES IpThreadAttributes, //SD(安全描述符)
SIZE_T dwStackSize, // initial stack size
LPTHREAD_START_ROUTINE IpStartAddress,// thread function
LPVOID IpParameter // thread argument
DWORD dwCreationFlags, // creation option
LPDWORD IpThreadld // thread identifier
);

dwStackSize 初识堆栈大小(如果不填写就是操作系统默认给一个值) IpStartAddress 当前线程真正执行的代码的地址 IpParameter 线程所需要的参数在哪(实质上是一个指针) dwCreationFlags 创建线程的一个标识(这个成员如果填0的话,可以立即进入执行的状态),或者用 CREATE_SUSPENDED这个宏标识的话,这个线程就会处于一个挂起的状态。除非使用 ResumeThread 这个API 解除挂起状态,这个线程都不会执行。 IpThreadld 这个成员是整个函数返回的线程ID(区别于这个函数的返回值是线程句柄)

我们利用CreateThread这个API 可以创建一个新的线程,而因为没有进行线程控制,会出现“分时段性的多线程”(上方有解释),即为一段时间执行这一段,另一段时间执行另一段。我们可以用下面这段代码进行测试。

#include<stdio.h>
#include<windows.h>
DWORD WINAPI ThreadProc(LPVOID IpParameter)
{
for(int i = 0;i<5;i++)
{
Sleep(500);
printf("+++++++++%d\n",i);
}
return 0;
}
?
int main()
{
HANDLE hThread;
hThread = CreateThread(NULL,0,ThreadProc,NULL,0,NULL);
CloseHandle(hThread);
?
for(int i = 0;i<5;i++)
{
Sleep(500);
printf("---------%d\n",i);
}
return 0;
}
?

③向线程函数传递变量

ThreadProc 这个函数我们称为线程函数,每次创建线程的时候都要提供这样一个函数,而且 这个函数有特定的格式要求(有一个参数有一个返回值)。(但是这个函数只是告诉代码的位置在哪,其他的函数类型都也能用,只不过需要强制转换类型,如果遵守格式要求就能够减少麻烦)

<1> 线程参数。

如果我们想要将参数传进线程函数的话,原定参数 IpParameter 是空指针类型的,我们可以通过强制转换类型,如下:

DWORD WINAPI ThreadProc(LPVOID IpParameter)
{
   int * p = (int *)IpParameter; //强制转化
   
for(int i = 0;i < *p;i++)
{
Sleep(500);
printf("+++++++++%d\n",i);
}
return 0;
}
?
int main()
{
HANDLE hThread;
   int n;
   
   n = 10;
hThread = CreateThread(NULL,0,ThreadProc,(LPVOID)&n,0,NULL);
CloseHandle(hThread);
?
for(int i = 0;i<5;i++)
{
Sleep(500);
printf("---------%d\n",i);
}
return 0;
}
?

<2> 全局变量。

但是在我们传递线程参数的时候需要注意的一件事:举个实例,就是上方这串代码我们传递的线程参数,是位于 main 函数中的,属于局部变量位于堆栈中,就需要保证当我们创建的这个线程执行的时候,当前的这个堆栈没有被回收,即需要创建的这个线程必须要在这个 main 函数执行结束之前执行。我们通常这样理解,我们如果需要向线程传递参数我们就需要保证,参数的存活时长要大于该线程的存活时长。或者我们可以使用全局变量,因为全局变量的生命周期是一直存在的。

10、线程控制

①如何让线程停下来?

让自己停下来: Sleep()函数 让别人停下来: SuspendThread()函数 线程恢复: ResumeThread()函数

Sleep函数的意义是,当线程执行到某个阶段的时候,我们期望它停下来,就可以利用Sleep函数。但是Sleep函数只能让当前自己的函数停下来。如果我们希望让别的线程停下来,我们就可以利用 SuspendThread 函数将线程挂起,挂起的意义就是当一个线程挂起的时候,它就处于堵塞状态了,将不再占用 CPU 的时间,在该线程恢复之前都会处于堵塞状态。即一直不占用 CPU 的时间。一个线程是可以被挂起多次的,但是挂起几次就得恢复几次。

②等待线程结束:

<1> WaitForSingleObject(); <2> WaitForMultipleObjects(); <3> GetExitCodeThread();

WaitForSingleObject()这个函数的意义是,程序到这个函数这里就会处于堵塞状态,直到传进来的句柄(进程、线程)的状态发生变更(执行完毕)或者耗尽设置的等待时间,才会恢复。

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

如果想要一直等待直到,线程执行完毕,就可以将第二个参数设置为宏(INFINITE)。

如果想要

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇c语言学习4 下一篇C语言:数据结构之单链表(三)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目