WIN32多线程程序设计学习笔记

银河麒麟V10等保加固清单:安全基线配置一篇搞定(附逐项检查表) 通过限制使用SSH直接以root身份登录,禁用公钥登录的方式加强SSH服务的安全性。更改SSH默认端口可在一定程度上防止被黑客使用大批量扫描方式攻击。通过修改SSH的配置文件限制可以使用SSH服务远程管理的主机。 阅读详情

WIN32多线程程序设计学习笔记(第二章) 

 

《WIN32多线程程序设计》这本书也看了好多遍,但总是觉得印象不深;我想是不是应该做做笔记,一来可以加深一下印象。二也在可以在用时方便查阅。J

 

首先,我觉得线程一点都不难(这样的心理暗示会使我觉得学的轻松一些);

why? 

与调用函数的过程类似;线程只不过用CreateThread的API将函数

HANDLE hThread = CreateThread (

LPSECURITY_ATTRIBUTES lpThreadAtt,

  DWORD dwStackSize

  LPTHREAD_START_ROUTINE lpFun,

  LPVOID lpParameter,

  DWORD dwCreationFlags,

  LPDWORD lpThreadID)

LpFun:就是指向被封装的函数的地址。

LpParameter: 就是指向被封装的函数的参数(没有参数填入null)

图示:

 

CreateThread()除了LpFun,LpParameter两个参数极为重要外,它的其它的参数有啥用的?当然的有用了,具体使用的时候查帮助就行了,实在不会,那就设为null得了。

当调用CreateThread()后,会产生线程核心对象(如果已经产生了线程核心对象,那么就只将此核心对象的引用计数加1;另外,win32系统中有若干种核心对象),并以句柄的方式代表它。那么,显然,在线程使用完毕后就应该用CloseHandle()函数关闭。

 

既然线程是独立的运行的程序,那么主程序如何知道线程执行完毕呢?答案是通过GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode)函数。如果线程已结束,那么线程结束的代码被放在lpExitCode参数中带回来,如果线程尚未结束,lpExitCode带回来的值是STILL_ACTIVE。

值得注意的是:GetExitCodeThread(HANDLE hThread,LPDWORD lpExitCode)还可以带回线程函数的返回值。lpExitCode就是函数的返回值

例:  

线程函数:

DWORD WINAPI ThreadFun(LPVOID n)

{

                        return  10;

}

           int main()

{

hThrd  = CreateThread(null,ThreadFun,…..);

DWORD  exitCode=0;

                 for(  ;  ;  ) 

              {

            GetExitCodeThread(hThrd,&exitCode);

           If ( exitCode ==  STILL_ACTIVE)

             {

                            //线程仍然在运行

                 }

                else

                {

                            break;

                }

}

//exitCode保存了函数的返回值10

printf(“线程函数的返回值: %d /n”, exitCode);

CloseHandle(hThrd);

Return 0;

         }

 

       这一章节的内容大概就是这么多,总结一下:

* 产生一个线程                  [  CreateThread()   ]

* 判断线程是否结束              [  GetExitCodeThread ()   ]

* 关闭线程                                  [  CloseHandle ()   ]

* 强制退出线程                  [  ExitThread ()   ]

 

 

WIN32多线程程序设计学习笔记(第三章)

 

通过在上一章的学习,我学会使用GetExitCodeThread()这个函数来判断一个线程是否还在执行。通过这个函数,我就可以对付“某个线程必须在某个线程结束后才能运行”的情况。复习一下:

程序片段:

              for  ( ; ; )

              {

                     int rc;

                     rc  =  GetExitCodeThread(hThrd,&exitCode);

                     if (!rc && exitCode != STILL_ACTIVE)

                            break;

              }

使用这个方法,必须持续不断的调用GetExitCodeThread(),直到其结果不再是STILL_ACTIVE。书上说这方法不好,很浪费cpu时间.,称为忙等待(busy waits)。忙等待必须应有的重视,不然你会发现当包含忙等待的程序运行起来后,其它正在进行的程序的反应就很迟钝了。因为cpu几乎用了所有的可用时间去检查线程是否结束。

 

那么,我应该怎么做呢?如何才更有效率呢?

 

另一种有效率的方法:

使用WaitForSingleObject()这个函数来完美的解决问题。

完成上面程序片段同样功能只需一句话:

WaitForSingleObject ( hThrd, INFINITE );

若hThrd线程没有结束时,调用这个函数的程序就会在函数调用点停下来,直到hThrd线程结束时(术语:hThrd被激发)才继续向下执行。

不知道大家会不会有这样疑问------这个函数不会只是把上面的程序片段包装了一下吧?它真是很有效率吗?如果它有效率,它是如何做到的呢?

可以告诉大家,WaitForSingleObject()不是上述程序片段的简单包装,它真的很有效率(不信,按书上的方法,打开性能管理器看看),至于它如何做到的,我也有兴趣知道(知道告诉我),我只知道这个函数得到了操作系统级的某些底层调度函数的支持。

 

基本上本章的核心内容就是以上所述了。(至于WaitForSingleObject()参数及返回值的说明,查书就行了,毋需多言)

  

具体的看一个实在的例子,胜过在此长篇大论,下面请看:

//参考书上例子

//程序的目的:只用3个线程,完成6件事

int main()

{

              HANDLE        hThrds[3];

 

              int slot = 0;

              For ( int I=1 ; I<=6 ; I++)

              {

                     if( I > 3 )

                     {//已经存在3个线程了

 

//等待其中的一个线程线束后,再创建线程做剩余的事情

//效率不高,因为线程结束的次序与它们被产生的次序不同

WaitForSingleObject( hThrds[slot] , INFINITE ) ;

CloseHandle ( hThrds[slot] );

                     }

 

                     //构造线程

                     hThrds[slot] = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);

                    

                     if (++slot>2)

                            slot=0;

}// end for

 

for ( slot=0; slot<3; slot++)

{

       //等待剩余的线程结束

       WaitForSingleObject( hThrds[slot] , INFINITE ) ;

       CloseHandle ( hThrds[slot] );

}// end for

}

 

上面的这段程序有一个问题,就是效率不是很高;理想的状况是,一旦有一个线程结束,就立刻产生一个线程补上。仔细读上面的程序,你会发现它无法实现理想的状况;因为它假设线程结束的次序会和它们被产生的次序相同。比如,当依序产生了1,2,3线程以后,一定是按1,2,3的次序结束。其实不然,也许2比1更早结束。在这时,上面的程序并不会立刻产生一个线程填补2,而是非要等1结束了,才产生线程。那么能够实现理想的状况吗?答案是可以,请用WaitForMultipleObjects() 函数, 这个函数的用法基本上与WaitForSingleObject()差不多,在这里我就不举例说明了。

 

本章最后还提到了MsgWaitForMultipleObjects() , 这个函数特点是在消息到达或线程结束时返回。

 

我想,只要用会了WaitForSingleObject()这个函数, 那么WaitForMultipleObjects()和MsgWaitForMultipleObjects()看一下也就会用了(书上举了两个小例子来说明,看一下花不了多少时间,不必我在这里废话了)。

 

这一章节的内容大概就是这么多,总结一下:

* 等待线程结束                  [  WaitForSingleObject()           ]

* 等待多个线程结束              [  WaitForMultipleObjects()                ]

* 等待多个线程结束或消息到达    [  MsgWaitForMultipleObjects()         ]

 

WIN32多线程程序设计学习笔记(第四章 上)

 

到目前为止,我已经知道如何创建线程,销毁线程及如何判断一个线程是否结束了;但运用线程,管理线程,如何使线程按自己意愿正确运行才是多线程程序设计的重点及难点。

 

大家知道,线程具有并发性,在同一时间段会存在多个线程,当这些线程同时存取同一数据时,就会有问题。就像在超市储物品一样,来的时候物品箱是空,转身拿物品准备储的时候,发现物品箱已被占用了。这时,物品箱就是我所说的同一数据,人指的就是线程了。

 

那么,如何让线程彼此互相合作,互不干扰呢?------协调线程的工作是由同步机制来完成的。正如书上所说:“有放多种同步机制可以运用。使用哪一种则完全视欲解决的问题而定。这些同步机制还能用各种方式组合在一起运用,以产生更精密的机制”。

 

首先,让我们看看最容易使用的一个同步机制;它包含同步机制的设计思想,拿握了它也就可以不费什么劲拿握其它的同步机制了。

1 :Critical Sections(关键区域、临界区域)

程序片段:

       CRITICAL_SECTION         gBoxKey  ;

       DWORD WINAPI ThreadFun(LPVOID n)

       {

              //进入关键区域 (情景:关上物品箱,拨下钥匙)

              EnterCreiticalSection (&gBoxKey ) ;(1)

                     //处理一些不可分割的操作。。。。。

                     //(情景:转身拿物品,储物品,去购物。。。。)

              //离开关键区域 (情景:打开物品箱,拿出储存的物品,插上钥匙)                

              LeaveCreiticalSection (&gBoxKey) ;(2)

       }

 

       void main()

       {

              //初始化全局锁 (情景:生成物品箱的钥匙)

              InitializeCriticalSection( &gBoxKey ) ;             

              //产生两个线程 (情景:准备两个人抢一个物品箱)

              HANDLE hMan1 = CreateThread(NULL,0,ThreadFun,…….);

              HANDLE hMan2 = CreateThread(NULL,0,ThreadFun,…….);

 

              CloseHandle(hMan1);

              CloseHandle(hMan2);

//删除全局锁 (情景:删除物品箱的钥匙)

              DeleteCriticalSection( &gBoxKey ) ;

       }

 

按照上面的程序,我在笔记开头所描述的“超市储物品”的情况是不会发生的,不会再有物品箱被人抢走的可能。由于线程的并发性,从我看到一个空箱子到我将物品的放入物品箱中的这段时间内的操作应该是不可分割的;否则,我看到的物品箱就随时会被人抢走。那么如何保证操作是连续、不可分割呢?简单:看到空箱子,关上箱子,拨下钥匙(1),这时,别人就没办法使用这个箱子了。当我不再需要箱子的时候,打开箱子,插入钥匙(2),就可以让别人使用了。上述就是多线程处理共享资源的一个基本思路。

 

2 :Mutexes(互斥器)

程序片段:

       HANDLE              hBoxKey  ;

       DWORD WINAPI ThreadFun(LPVOID n)

       {

              //进入关键区域 (情景:关上物品箱,拨下钥匙)

              WaitForSingleObject ( hMutex,INFINITE ) ;(1)

                     //处理一些不可分割的操作。。。。。

                     //(情景:转身拿物品,储物品,去购物。。。。)

              /离开关键区域 (情景:打开物品箱,拿出储存的物品,插上钥匙)                

              ReleaseMutex ( hMutex ) ;(2)

       }

 

       void main()

       {

              //初始化全局锁 (情景:生成物品箱的钥匙)

              hBoxKey = CreateMutex(       NULL,FALSE,NULL );          

              //产生两个线程 (情景:准备两个人抢一个物品箱)

              HANDLE hMan1 = CreateThread(NULL,0,ThreadFun,…….);

              HANDLE hMan2 = CreateThread(NULL,0,ThreadFun,…….);

 

              CloseHandle(hMan1);

              CloseHandle(hMan2);

 //删除全局锁 (情景:删除物品箱的钥匙)

              DeleteCriticalSection( &gBoxKey ) ;

       }

 

按照上面的程序,我在笔记开头所描述的“超市储物品”的情况是不会发生的,不会再有物品箱被人抢走的可能。由于线程的并发性,从我看到一个空箱子到我将物品的放入物品箱中的这段时间内的操作应该是不可分割的;否则,我看到的物品箱就随时会被人抢走。那么如何保证操作是连续、不可分割呢?简单:看到空箱子,关上箱子,拨下钥匙(1),这时,别人就没办法使用这个箱子了。当我不再需要箱子的时候,打开箱子,插入钥匙(2),就可以让别人使用了。上述就是多线程处理共享资源的一个基本思路。

 

2 :Mutexes(互斥器)

程序片段:

       HANDLE              hBoxKey  ;

       DWORD WINAPI ThreadFun(LPVOID n)

       {

              //进入关键区域 (情景:关上物品箱,拨下钥匙)

              WaitForSingleObject ( hMutex,INFINITE ) ;(1)

                     //处理一些不可分割的操作。。。。。

                     //(情景:转身拿物品,储物品,去购物。。。。)

              /离开关键区域 (情景:打开物品箱,拿出储存的物品,插上钥匙)                

              ReleaseMutex ( hMutex ) ;(2)

       }

 

       void main()

       {

              //初始化全局锁 (情景:生成物品箱的钥匙)

              hBoxKey = CreateMutex(       NULL,FALSE,NULL );          

              //产生两个线程 (情景:准备两个人抢一个物品箱)

              HANDLE hMan1 = CreateThread(NULL,0,ThreadFun,…….);

              HANDLE hMan2 = CreateThread(NULL,0,ThreadFun,…….);

 

              CloseHandle(hMan1)

              CloseHandle(hMan2);

  //删除全局锁 (情景:删除物品箱的钥匙)

              CloseHandle( hBoxKey ) ;

       }

看到没?无论从共享资源的思路了,还是从程序代码的编制上,使用Mutexes与使用Critical Sections几乎都没有什么区别;但作为 Mutexes机制的提出肯定是有其原因的;我们来看这样的一个情形,当我拿走钥匙以后,因为某些因素再也不能回来了,那么这个箱子便再也不能被使用。也就是说,进入Critical Sections线程若中途当掉了,那么别了线程是再也进不了Critical Sections(一个资源就这样浪费了),那些需要进入Critical Sections的线程会停在入口不再执行,线程永远都结束不了。

怎么办?(用WaitForSingleObject解决)

还记得上一章学过的WaitForSingleObject吗?上一章主要用它等待线程的结束,但这个函数的作用不仅限于此,在这里,我们再前进一小步,探究WaitForSingleObject这个函数的妙用。

原型:

DWORD WaitForSingleObject ( HANDLE  hObject ,DWORD  time ) ;

hObject:等待对象的handle(代表一个核心对象),在上一章中代表线程handle,注意没有,hObject是代表一个核心对象,也就是说,只要是核心对象,WaitForSingleObject都能处理,处理的原则是“当核心对象被激发时,函数返回”(有多少种核心对象?及核心对象对激发的定义见书P76)。

在这里,我遇到了一个叫mutex核心对象,mutex对激发的定义是:“当没有任何线程拥有该mutex,而且有一个线程正以Wait…()等待该mutex,该mutex就会短暂地出现激发状态,使Wait…()得以返回, 那么在其它的情况,mutex处于未激发状态 ”。

 

好了,我们又进一步的了解了WaitForSingleObject函数,那么,如何解决Critical Sections所遇到的因难呢?当拥有mutex的线程结束前没有调用ReleaseMutex(不管该线程是当了,还是忘记调用ReleaseMutex),那么其它正以WaitForSingleObject()等待此mutex的线程就会收到WAIT_ABANDONED_0。有了这个值,我就解开难题了。

程序片段:

DWORD        rc    =       WaitForSingleObject( hMutex ) ;

If ( rc  == WAIT_OBJECT_0 )

{

              //正常的处理

}

else

{

              If ( rc  == WAIT_ABANDONED_0 )

{

                     //没有正常的释放mutex(比如拥有mutex的线程死了)

}

}

 

我想,从笔记的角度来看,上面对mutex描述已经可以帮助我很快的上手使用了,至于对mutex更详细的说明,还是要看看书.。(当然,希望我的这一段描述能帮助你理解mutexJ)

      

总结一下:

CRITICAL_SECTION                              Mutex 核心对象

 

InitializeCriticalSection()                                   CreateMutex()

 

 

WIN32多线程程序设计学习笔记(第四章 下 第五章)

 

终于又看<<WIN32多线程程序设计>>了;开卷有益,今天看了第四章后半部分,感觉颇有收获;以前对EVENT这个核心对象,用起来总是心中没底,看了EVENT的介绍也是似懂非懂的。哈!今天看了以后,真有神助,我觉得应该是搞懂了(自以为事J)。仔细想想,应该是记笔记的功劳,用脑筋写过的东西还真是不容易忘记咧!!!不但印象深刻,而且助我理解了EVENT。

 

好了,闲话少说,进入正题吧!

从第三章以来,每一章都必不可少的用到了一个重要的函数,知道是什么吗?

――――WaitFor…. ()系列

//快速复习

判断一个线程是否结束:WaitForSingleObject ( HANDLE hthred …. );

判断是否能够进入关键区域:WaitForSingleObject ( hMutex….) ;

 

Wait….()会在核心对象被激发时返回,各种核心对象对激发的定义不甚相同,对于hthred而言,线程结束,意味着核心对象被激发;对于hMutex而言, hMutex不再被其它任何线程使用,意味着核心对象被激发。反正对于各种核心对象而言,一定是有某种场景的出现使得核心对象被激发,除了EVENT这个核心对象。

 

对于EVENT这个核心对象而言,它的激发状态完全由程序来控制,也就是说,由自己来控制EVENT的激发或未激发状态( 通过SetEvent() , ResetEvent() )。当线程1因调用Wait…(hEvent)而被阻塞后,一定是某个线程调用了SetEvent( hEvent )使hEvent被设为激发状态,从而使线程1被解除阻塞继续向下运行,具体的运用参见下表:

 

函数

EVENT对象[Manual方式产生]

EVENT对象[Auto方式产生]

Wait…()

当EVENT对象变为激发状态(使得因调用Wait…()而等待的线程被唤醒)之后,不会被重置为非激发状态(必须调用ResetEvent())

当EVENT对象变为激发状态(使得因调用Wait…()而等待的线程被唤醒)之后,自动重置为非激发状态

SetEvent()

把EVENT对象设为激发状态

把EVENT对象设为激发状态

ResetEvent()

把EVENT对象设为非激发状态

把EVENT对象设为非激发状态

PulseEvent()

把EVENT对象设为激发状态,唤醒“所有”等待中的线程,然后把EVENT对象设为非激发状态

把EVENT对象设为激发状态,唤醒“一个”等待中的线程,然后把EVENT对象设为非激发状态

[使用CreateEvent () API函数构造EVENT核心对象,CreateEvent ()的第二个参数决定了产生的EVENT对象是Manual(手工)方式还是Auto(自动)方式;第三个参数决定了决定了产生的EVENT对象初始状态是激发还是未激发]

 

EVENT核心对象的不同的状态(初始状态是激发还是未激发)及不同的类型(Manual[手工]方式还是Auto[自动]),与之对应的处理方式也就不一样,情况太多了真是不好一一举例,以后补上J(在下面第五章中,我举了一个例子)

 

值得注意:使用PulseEvent()方法激发EVENT的请求可能会被遗失,由此可能产生的一系列问题在P124有很精彩的描述,值得一看(由此描述引出了semaphore同步机制)。

 

至此,第四章差不多可以结束了(除了semaphore,Interlocked ,自己看一下吧!)

 

下面进入第五章:

 

如何强制结束一个线程?查查有关线程的API函数,立刻便找到一个结束线程的函数―――――TerminateThread ( ) ; 用它吗?

噢!不要使用它。被TerminateThread ( )强制结束的线程可能会有造成以下后果:

1、  没有机会在自己结束前释放自己所使用的资源

2、  可能引起内存泄漏

3、  如果这个线程被结束时处于一个critical section之中,那么该critical section将因此永远处于锁定状态。

 

那么如何强制结束一个线程?书上给出了一个例子,以后强制结束一个线程就靠它了。

程序片段:

//线程退出事件

HANDLE hExitEvent = null ;

//一个需要长时间运行的线程

DWORD WINAPI ThreadFun ( LPVOID p )

{

       for (  int I =0 ; I < 1000000; I++ )

       {

       //判断线程是否要被强制结束

/*  可能在这里大家有点疑惑 ,如果没有调用SetEvent()的方法,

hExitEvent不是总处于未激发状态吗?哪线程不就停在这里不动了?

答案是:这里用到了P74提到的一个Wait….()一个用法,当time_out

为0,检查hExitEvent的状态,如果hExitEvent处于未激发状态,

立刻返回WAIT_TIMEOUT,如果hExitEvent处于激发状态,则立刻

返回WAIT_OBJECT_0。*/

if ( WaitForSingleObject ( hExitEvent , 0 ) !=WAIT_TIMEOUT )

{

       //做一些退出线程前的清理工作

       return (DWORD) –1 ;

}

              //做一些极其消耗时间的处理….

              //…….

              //……..

       }

}

void main()

{            

              HANDLE hThrd;

//构造EVENT核心对象,初始状态处于未激发状态,Manual方式

              hExitEvent = CreateEvent ( NULL,TRUE,FALSE,NULL ) ;

//线程启动

              hThrd  = CreateThread ( null,ThreadFun,…..);

              //等待了很久,实在等不下去了,发出结束线程退出事件(激发EVENT核心对象)

              //迫使线程结束

              SetEvent ( hExitEvent ) ;

       //等待线程结束

       WaitForSingleObject (hThrd,… );

       CloseHandle ( hThrd );

}

 

下面接着谈到了线程的优先权,调整线程优先权很简单,无非就是用SetThreadPriority()和GetThreadPriority()等函数。但如何有效,合理的调整线程的优先权却是一个复杂的问题,正如书上所说,“如果你的目标是保持简单,那就还是避免处理[优先权]这个烫山芋吧“。

 

rc = GetOverlappedResult(

 

继续。。。

上面的程序片段使用WaitForMultipleObjects函数来等待,会有两个问题:

第一、     只能等待小于64个的对象,这是WaitForMultipleObjects函数本身所带来的限制。

第二、     你必须不断根据“哪一个handle被激发”而计算如何处理。那个这个程序的结构可不是很清晰,以后维护可不方便

 

那么书上在这里提供了一个异步过程调用(APCs)的方法来解决这些问题

 

APCs的核心观点是:提供一个函数,当overlapped I/O操作完成时,自动调用此函数

注意:运用APCs,必须使用ReadFileEx()、WriteFileEx ()

例子:

//自定义函数,供overlapped I/O操作完成时调用

VOID WINAPI MyFunc(DWORD dwErrorCode,  //完成码

    DWORD dwNumberOfBytesTransfered,    // 被传递的字节数目

    LPOVERLAPPED lpOverlapped   //指向OVERLAPPED 结构的指针

 )

{

    //这里运用了一个技巧,因为使用APCs技术;那么OVERLAPPED 结构的

    //event栏位没有什么用,可以用它来传递一些参数。

//在这里利用它传递序号,以表明是谁完成了overlapped I/O

    int nIndex = (int)(lpOverlapped->hEvent);

    //针对nIndex,做一些操作

    switch ( nIndex )

    {

        case 1 :  //做一些操作。。。 break;

case 2 :  //做一些操作。。。 break;

…..

    }

//如果所有overlapped I/O都处理完毕,将全局event激发,使主程序结束

    if (++nCompletionCount == MAX_REQUESTS)

        SetEvent(ghEvent);

}

int main()

{

    //构造全局event

    ghEvent=CreateEvent(NULL,TRUE,FALSE, NULL );

// 以overlapped的方式打开文件

    ghFile = CreateFile( szPath,

                    GENERIC_READ,

                    FILE_SHARE_READ|FILE_SHARE_WRITE,

                    NULL,

                    OPEN_EXISTING,

                    FILE_FLAG_OVERLAPPED,

                    NULL

     );

    for (i=0; i<MAX_REQUESTS; i++)

     {

        //将同一文件按几个部分按overlapped方式同时读

        //注意看QueueRequest函数是如何运做的

        QueueRequest(i, i*16384, READ_SIZE);

     }

      // 等待所有操作完成

      WaitForSingleObjectEx(ghEvent, INFINITE, TRUE );

 

封装起来,并产生一个与主程序同时执行的程序来调用被封装的函数。

YOLOv13改进策略【注意力机制篇】| ICASSP 2023 EMA 高效多尺度注意力,跨空间学习提高远距离建模依赖 ICASSP 2023 EMA 高效多尺度注意力在 YOLOv13 的接入实战:跨空间学习提升远距离依赖建模,含原理图解、完整代码、yaml 配置与实测参数量对比(ultralytics 8.3.63)。 阅读详情

相关推荐

GD32H7 SPI驱动实战:手把手教你用SPI3连接外部Flash(W25Q128)并实现读写

本文详细介绍了基于GD32H7系列MCU的SPI3接口驱动W25Q128外部Flash的全流程开发指南。从硬件设计、引脚配置到SPI3外设深度配置,再到底层通信函数实现和高级功能优化,提供了完整的解决方案。特别针对高速读取、DMA传输和信号完整性等关键环节进行了优化,确保系统在-40℃~85℃范围内稳定工作。

weixin_28729205的博客 379

WIN32多线程程序设计学习笔记(第二章) 收藏

<br />WIN32多线程程序设计学习笔记(第二章) 收藏 <br />  <br />WIN32多线程程序设计学习笔记(第二章)<br /> <br />《WIN32多线程程序设计》这本书也看了好多遍,但总是觉得印象不深;我想是不是应该做做笔记,一来可以加深一下印象。二也在可以在用时方便查阅。J<br /> <br />首先,我觉得线程一点都不难(这样的心理暗示会使我觉得学的轻松一些);<br />why?  <br />与调用函数的过程类似;线程只不过用CreateThread的API将函数<br /

looob的专栏 535

rv1126平台spi屏调试

st7789v2 i2c调试

zuoanyouzhuan_的博客 2035

WIN32多线程程序设计学习笔记(第二章)

  WIN32多线程程序设计学习笔记(第二章) 《WIN32多线程程序设计》这本书也看了好多遍,但总是觉得印象不深;我想是不是应该做做笔记,一来可以加深一下印象。二也在可以在用时方便查阅。J 首先,我觉得线程一点都不难(这样的心理暗示会使我觉得学的轻松一些);why?  与调用函数的过程类似;线程只不过用CreateThread的API将函数封装起来,并产生一个与主

chinani的专栏 2721

CSP-J 入门级第一轮认证 2025 详细解析

2025年CSP-J入门级第一轮认证模拟赛提供10套免费试题,含选择题与解析。选择题涉及计算机科学基础,如32位无符号整数最大值计算(约42.9亿,选A)、C++位运算(255&254=254,选B)、递归函数分析(calc(5)=6,选B)、哈夫曼树构造(带权路径长度186,选B)等。其他题目涵盖图论(有向图边数等于入度/出度和,选B)、组合数学(120种选法,选C)、布尔逻辑(选项C不恒等)、模运算周期性(f[2025]=6,选D)、C++字符串特性(支持string+char,选B)及引用传参

lan_in的博客 2939

【毕业设计之python系列】基于Flask的在线音乐网设计与实现

本论文旨在通过使用Python的Web框架Flask,设计和实现一个具有完整功能的在线音乐网站。该网站包括用户注册、登录、注销、歌曲上传、编辑、删除、歌单创建、编辑、删除、评论、搜索、音乐播放等功能,并针对不同用户角色(如普通用户、管理员)实现了不同的权限管理。同时,本论文还介绍了如何使用第三方API(如网易云音乐API)获取歌曲信息等技术实现。在设计上,本论文采用了MVC(Model-View-Controller)架构模式,将后端数据处理与前端展示分离,以便于代码的管理和维护。在数据库设计方面,本论文设

m0_56073435的博客 3242

WIN32多线程程序设计学习笔记(第四章 上)

WIN32多线程程序设计学习笔记(第四章 上) 到目前为止,我已经知道如何创建线程,销毁线程及如何判断一个线程是否结束了;但运用线程,管理线程,如何使线程按自己意愿正确运行才是多线程程序设计的重点及难点。 大家知道,线程具有并发性,在同一时间段会存在多个线程,当这些线程同时存取同一数据时,就会有问题。就像在超市储物品一样,来的时候物品箱是空,转身拿物品准备储的时候,发现物品箱

chinani的专栏 2148

智驾芯片新天团!NVIDIA Thor vs 高通8797 vs 蔚来神玑NX9031,2025-2026谁能称王?

应用场景推荐芯片理由高阶NOA + L4 Robotaxi千TOPS以上,满足BEV+TransformerL2+/L3级别NOAThor-U / 高通8797算力适中,功耗控制佳,生态成熟经济型城市NOAThor-Z / S性价比均衡,适合前装普及自研平台一体化NX9031华为之外最强自研整合方案📌 TOPS不再是天花板,GPU、带宽、功耗、上市时间和车企绑定都是决胜关键📌 Thor系列仍然统治高端,但国产神经元开始觉醒📌 智驾芯片的选择,从“强”走向“适合场景”

weixin_43199439的博客 2636

WIN32多线程程序设计学习笔记(第四章 下 第五章)

WIN32多线程程序设计学习笔记(第四章 下 第五章) 终于又看多线程程序设计>>了;开卷有益,今天看了第四章后半部分,感觉颇有收获;以前对EVENT这个核心对象,用起来总是心中没底,看了EVENT的介绍也是似懂非懂的。哈!今天看了以后,真有神助,我觉得应该是搞懂了(自以为事J)。仔细想想,应该是记笔记的功劳,用脑筋写过的东西还真是不容易忘记咧!!!不但印象深刻,而且助我理解了EVENT。

chinani的专栏 2189

基于Simulink的鲸鱼优化算法(WOA)MPPT仿真

摘要:本文介绍了基于Simulink的鲸鱼优化算法(WOA)在光伏MPPT控制中的应用。WOA模拟座头鲸的"气泡网捕食策略",通过包围猎物、螺旋收缩和随机搜索三阶段动态平衡全局探索与局部开发能力,有效解决局部阴影导致的多峰P-V曲线问题。文章详细讲解了WOA-MPPT的Simulink建模过程,包括多峰光伏阵列建模、WOA控制器实现和Boost变换器控制。仿真结果显示,在三种典型工况下,WOA-MPPT的追踪效率>99.3%,动态响应时间<0.15s,性能优于传统算法。最后提出了混合WO

amy_mhd的博客 71

二、NovAtel Connect 2.3.2 版本 操作说明

一、连接方式 有 串口连接、USB连接、蓝牙连接、无线网连接、网口连接,具体的连接方式看博客: https://blog.youkuaiyun.com/hltt3838/article/details/110622732 下面具体的介绍一下 串口的连接方式: 接收机有三个串口,COM1、COM2、COM3,看上面的连接就知道了! 并且有三个对应的线,1 2 3 ; 把线和串口对应连接,串口的另一端和电脑连接,当然如果电脑没有串口,可以用 串口转USB,如线图所示: (当然,一定要连接电源呀) ...

努力努力努力 4382

WIN32多线程程序设计学习笔记(第三章)

WIN32多线程程序设计学习笔记(第三章) 通过在上一章的学习,我学会使用GetExitCodeThread()这个函数来判断一个线程是否还在执行。通过这个函数,我就可以对付“某个线程必须在某个线程结束后才能运行”的情况。复习一下:程序片段:              for  ( ; ; )              {                     int r

chinani的专栏 2427

ImportError: DLL load failed while importing _pydantic_core: 找不到指定的程序对应解决方案

本文主要介绍了ImportError: DLL load failed while importing _pydantic_core: 找不到指定的程序对应解决方案,希望能对使用Python的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 19万+

Win32API多线程程序设计学习笔记

http://blog.sina.com.cn/s/blog_499b249c010003nw.html    Win32API多线程程序设计学习笔记 CreateThread 函数功能:该函数创建一个在调用进程的地址空间中执行的线程。 函数原型:  HANDLE  CreateThread (  LPSECURITY_ATTRIBUTES lpThreadAttributes,

孙建军的博客 950

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

WIN32多线程程序设计学习笔记(第六章 上)

WIN32多线程程序设计学习笔记(第六章 上) 我们知道当程序调用I/O设备处理一些事情时,让主程序停下来干等I/O的完成是没有效率的。对这个问题有下面几种解决方法:方法一:使用另一个线程进行I/O。但从以前的学习中也知道,协调线程间的关系是一件麻烦的事情,需要小心的设计;所以这个方案可行,但是麻烦。方法二:使用overlapped I/O。正如书上所说:“overlapped I

chinani的专栏 2089

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

WIN32多线程程序设计学习笔记[转]

 《WIN32多线程程序设计》这本书也看了好多遍,但总是觉得印象不深;我想是不是应该做做笔记,一来可以加深一下印象。二也在可以在用时方便查阅。J    首先,我觉得线程一点都不难(这样的心理暗示会使我觉得学的轻松一些); why?  与调用函数的过程类似;线程只不过用CreateThread的API将函数 HANDLE hThread = CreateThread (

sc_valentine21的专栏 2403

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

《Win32多线程程序设计》学习笔记---(1)

        最近开始看《Win32多线程程序设计》 ,感觉受益匪浅,写出来的目的有两个;一是想看看自己理解的程度,能否总结出作者真正想表达的内容。2是与大家共享。好了,废话就不说那么多了!文章开始讲述了操作系统的演化,作者从早期的MS-DOS1.0版本单任务系统到2.x的可以允许常驻程序(TSR),但是MS-DOS视其为自己的一部分,不是一个应用程序或是一个进程。随后提及到了拥有合作型多任

hada1234的专栏 846

《Win32多线程程序设计》读后感

吐槽一句,纯粹把csdn的博客当成笔记本了。         这个月读的书籍是《Win32多线程程序设计》,忘了在那儿看到推荐这本书的,结果去图书馆一查2002年出版的,在图书馆找到这本书时把我吓着了,封面都掉了,可以想象它的历史有多悠久。。。        只随便翻了几页就决定这个月就是它了,原因很简单,它将与多线程相关的很多概念将的很简单易懂,之前学习多线程相关的知识时很重要的一个问题就是

985

《Win32多线程程序设计》学习笔记---(合集)

小记:        当口上需要写一个p2p程序,设计底层线程结构时,想用事件去控制多线程的调度。可惜看书的年代太久远了,实在记不起来event中的set/reset的那些区别,只好上网搜索。发现这位未知名仁兄的文章写的实在清楚,不敢独享,转贴如下: 转自 http://www.diybl.com/course/3_program/c++/cppjs/2007918/71872.htm

理性的幻想 1072

《win32多线程程序设计》学习笔记三

一、Busy Waiting 1、绝对不要再win32中使用Busy Loop 二、性能呢监视器(略) 三、等待一个线程结束 1、Win32提供函数WaitForSingleObject(),他能够在某个线程结束时被调用。 2、获得一个线程对线的handle后,WaitForSingleObject()要求操作系统让即将等待的线程睡觉,直到以下任何

一世豁然的专栏 809

《win32多线程程序设计》学习笔记四

一、Critical Sections

一世豁然的专栏 1047

《win32多线程程序设计》学习笔记二

一、产生一个线程 1、产生一个线程(并因而成就一个多线程程序),是以CreateThread()函数作为开始。此函数原型如下: 二、使用多线程的结果 1、多线程程序无法预期   2、执行顺序无法保证 3、线程对于小的改变有高度的敏感 4、线程并不总是立即启动 三、核心对象 1、CreateThread()传回来的handle

一世豁然的专栏 670

Win32多线程程序设计学习笔记 1

1.1创建多线程的函数HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, //新线程的Security属性,NULL表示缺省DWORD dwStackSize,                                               //线程拥有自身堆栈大小 0默认表示1MLPTH

peterpans的专栏 836
上一篇: FTP协议(指令集)
下一篇: C/C++笔试题
code09
博客等级 码龄18年 31粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值