Win32 API 常用函数之一

来源:互联网 发布:javascript图书 知乎 编辑:程序博客网 时间:2024/05/21 06:55
 【线程】
       创建线程的函数是CreateThread,其原型如下:
HANDLE WINAPI CreateThread
(
  LPSECURITY_ATTRIBUTES lpThreadAttributes, 
  SIZE_T dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID lpParameter,
  DWORD dwCreationFlags,
  LPDWORD lpThreadId
);
       参数说明:
  1. 第一个参数关于安全性,通常值为NULL。Windows会设置为默认安全级别。
  2. 第二个参数关于堆栈大小,(关于线程的堆栈,以后有机会一定仔细学习)对于简单应用,同安全性相同,使用默认的大小即可,一般传入0。
  3. 第三个参数是线程函数名,用于指明想要新线程执行的线程函数的地址。线程函数可以使用任何名字。实际上,如果在应用程序中拥有多个线程函数,必须为它们赋予不同的名字,否则编译器/链接程序会认为你为单个函数创建了多个实现函数。
  4. 第四个参数是线程函数的传入参数,在线程启动执行时将该参数传递给线程函数。该参数提供了一个将初始化值传递给线程函数的手段。该初始化数据既可以是数字值,也可以是指向包含其他信息的一个数据结构的指针。
  5. 第五个参数是设定用于控制创建线程的其他标志。它可以是两个值中的一个。如果该值是0,那么线程创建后可以立即进行调度。如果该值是CREATE_SUSPENDED,系统可以完整地创建线程并对它进行初始化,但是要暂停该线程的运行,这样它就无法进行调度。
  6. 第六个参数是线程的ID,当传入NULL时,表示并不关心线程的ID。
  7. 返回值:线程函数必须返回一个值,它将成为该线程的退出代码。
       线程函数(实际上是你的所有函数)应该尽可能使用函数参数和局部变量。当使用静态变量和全局变量时,多个线程可以同时访问这些变量,这可能破坏变量的内容。然而,参数和局部变量是在线程堆栈中创建的,因此它们不太可能被另一个线程破坏。
       在实际coding中,根据线程的作用,可以把线程封装在一个类里,如果需要让线程唯一,那么线程函数应该为static的;如果想让线程不唯一,那么就需要以成员函数的形式传入。不论上述两种情况的哪一种,都可以让第四个参数传入this,这样做比较方便。
       如果线程能够返回,就可以确保下列事项的实现:
  1. 在线程函数中创建的所有C + +对象均将通过它们的撤消函数正确地撤消。
  2. 操作系统将正确地释放线程堆栈使用的内存。
  3. 系统将线程的退出代码(在线程的内核对象中维护)设置为线程函数的返回值。
  4. 系统将递减线程内核对象的使用计数。
       ExitThread和TerminateThread都可以作为线程退出的函数,不过区别明显:
       ExitThread函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是,C++资源(如C++类对象)将不被撤消。
       TerminateThread函数终止线程时,会造成如下结果:不会对关键代码段对象进行操作,也就是说,如果线程中存在关键代码段,那他不会被销毁。分配的资源也不会从堆中撤销。线程状态被设置成inconsistent。当线程终止运行时,DLL通常接收通知。但使用TerminateThread 强迫线程终止,DLL就不接收通知。

【关键代码段】
       CRITICAL_SECTION变量被用于控制多线程访问共享区的互斥行为。
       在使用关键代码段之前,要对CRITICAL_SECTION进行初始化,调用Initialize函数,需要使用互斥时调用Enter函数,结束互斥行为时使用Leave函数,销毁变量时使用Delete函数,原型如下:
void InitializeCriticalSection( 
  LPCRITICAL_SECTION lpCriticalSection 
); 
void EnterCriticalSection( 
  LPCRITICAL_SECTION lpCriticalSection 
); 
void LeaveCriticalSection( 
  LPCRITICAL_SECTION lpCriticalSection 
); 
void DeleteCriticalSection( 
  LPCRITICAL_SECTION lpCriticalSection 
); 
    EnterCriticalSection函数负责查看该结构中的成员变量。这些变量用于指明当前是哪个变量正在访问该资源。如果成员变量指明,调用线程已经被赋予对资源的访问权,那么EnterCriticalSection便更新这些变量,以指明调用线程多少次被赋予访问权并立即返回,使该线程能够继续运行。
    如果成员变量指明,一个线程(除了调用线程之外)已被赋予对资源的访问权,那么
EnterCriticalSection将调用线程置于等待状态。这种等待的线程不会浪费任何CPU时间。系统能够记住该线程想要访问该资源并且自动更新CRITICAL_SECTION的成员变量,一旦目前访问该资源的线程调用LeaveCriticalSection函数,该线程就处于可调度状态。
   
LeaveCriticalSection要查看该结构中的成员变量。该函数每次计数时要递减1,以指明调用线程多少次被赋予对共享资源的访问权。如果该计数大于0,那么LeaveCriticalSection不做其他
任何操作,只是返回而已。如果该计数变为0,它就要查看在调用
EnterCriticalSection中是否有别的线程正在等待。如果至少有一个线程正在等待,它就更新成员变量,并使等待线程中的一个线程(“公正地”选定)再次处于可调度状态。如果没有线程正在等待,LeaveCriticalSection函数就更新成员变量,以指明没有线程正在访问该资源。
    如果不想等,想得到要么能够使用资源,要么去做别的事情的方法,就用Try
EnterCriticalSection,当能够使用资源时,该函数返回TRUE,不能时返回FALSE。他不会把自己加入等待队列中去。

    使用关键代码段时有一些技巧:
  1. 每个共享资源使用一个CRITICAL_SECTION变量,如果应用程序中拥有若干个互不相干的数据结构,应该为每个数据结构创建一个CRITICAL_SECTION变量。这比只有单个CRITICAL_SECTION结构来保护对所有共享资源的访问要好(效率高)。
  2. 当同时访问多个资源时,必须始终按照完全相同的顺序请求对资源的访问。
  3. 不要长时间运行关键代码段,当一个关键代码段长时间运行时,其他线程就会进入等待状态,这会降低应用程序的运行性能。




原创粉丝点击