科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件深入浅出Win32多线程程序设计之线程控制

深入浅出Win32多线程程序设计之线程控制

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

WIN32线程控制主要实现线程的创建、终止、挂起和恢复等操作,这些操作都依赖于WIN32提供的一组API和具体编译器的C运行时库函数。

作者:宋宝华 来源:天极开发 2007年10月16日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
5.设置线程优先级

  当一个线程被首次创建时,它的优先级等同于它所属进程的优先级。在单个进程内可以通过调用SetThreadPriority函数改变线程的相对优先级。一个线程的优先级是相对于其所属进程的优先级而言的。

BOOL SetThreadPriority(HANDLE hThread, int nPriority);

  其中参数hThread是指向待修改优先级线程的句柄,线程与包含它的进程的优先级关系如下:

   线程优先级 = 进程类基本优先级 + 线程相对优先级

  进程类的基本优先级包括:

  (1)实时:REALTIME_PRIORITY_CLASS;

  (2)高:HIGH _PRIORITY_CLASS;

  (3)高于正常:ABOVE_NORMAL_PRIORITY_CLASS;

  (4)正常:NORMAL _PRIORITY_CLASS;

  (5)低于正常:BELOW_ NORMAL _PRIORITY_CLASS;

  (6)空闲:IDLE_PRIORITY_CLASS。

  我们从Win32任务管理器中可以直观的看到这六个进程类优先级,如下图:


  线程的相对优先级包括:

  (1)空闲:THREAD_PRIORITY_IDLE;

  (2)最低线程:THREAD_PRIORITY_LOWEST;

  (3)低于正常线程:THREAD_PRIORITY_BELOW_NORMAL;

  (4)正常线程:THREAD_PRIORITY_ NORMAL (缺省);

  (5)高于正常线程:THREAD_PRIORITY_ABOVE_NORMAL;

  (6)最高线程:THREAD_PRIORITY_HIGHEST;

  (7)关键时间:THREAD_PRIOTITY_CRITICAL。

  下图给出了进程优先级和线程相对优先级的映射关系:


  例如:

HANDLE hCurrentThread = GetCurrentThread();
//获得该线程句柄
SetThreadPriority(hCurrentThread, THREAD_PRIORITY_LOWEST);

  6.睡眠

VOID Sleep(DWORD dwMilliseconds);

  该函数可使线程暂停自己的运行,直到dwMilliseconds毫秒过去为止。它告诉系统,自身不想在某个时间段内被调度。

  7.其它重要API

  获得线程优先级

  一个线程被创建时,就会有一个默认的优先级,但是有时要动态地改变一个线程的优先级,有时需获得一个线程的优先级。

Int GetThreadPriority (HANDLE hThread);

  如果函数执行发生错误,会返回THREAD_PRIORITY_ERROR_RETURN标志。如果函数成功地执行,会返回优先级标志。

  获得线程退出码

BOOL WINAPI GetExitCodeThread(
 HANDLE hThread,
 LPDWORD lpExitCode
);

  如果执行成功,GetExitCodeThread返回TRUE,退出码被lpExitCode指向内存记录;否则返回FALSE,我们可通过GetLastError()获知错误原因。如果线程尚未结束,lpExitCode带回来的将是STILL_ALIVE。

获得/设置线程上下文
BOOL WINAPI GetThreadContext(
 HANDLE hThread,
 LPCONTEXT lpContext
);
BOOL WINAPI SetThreadContext(
 HANDLE hThread,
 CONST CONTEXT *lpContext
);

  由于GetThreadContext和SetThreadContext可以操作CPU内部的寄存器,因此在一些高级技巧的编程中有一定应用。譬如,调试器可利用GetThreadContext挂起被调试线程获取其上下文,并设置上下文中的标志寄存器中的陷阱标志位,最后通过SetThreadContext使设置生效来进行单步调试。

  8.实例

  以下程序使用CreateThread创建两个线程,在这两个线程中Sleep一段时间,主线程通过GetExitCodeThread来判断两个线程是否结束运行:

#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>

DWORD WINAPI ThreadFunc(LPVOID);

int main()
{
 HANDLE hThrd1;
 HANDLE hThrd2;
 DWORD exitCode1 = 0;
 DWORD exitCode2 = 0;
 DWORD threadId;

 hThrd1 = CreateThread(NULL, 0, ThreadFunc, (LPVOID)1, 0, &threadId );
 if (hThrd1)
  printf("Thread 1 launched\n");

 hThrd2 = CreateThread(NULL, 0, ThreadFunc, (LPVOID)2, 0, &threadId );
 if (hThrd2)
  printf("Thread 2 launched\n");

 // Keep waiting until both calls to GetExitCodeThread succeed AND
 // neither of them returns STILL_ACTIVE.
 for (;;)
 {
  printf("Press any key to exit..\n");
  getch();

  GetExitCodeThread(hThrd1, &exitCode1);
  GetExitCodeThread(hThrd2, &exitCode2);
  if ( exitCode1 == STILL_ACTIVE )
   puts("Thread 1 is still running!");
  if ( exitCode2 == STILL_ACTIVE )
   puts("Thread 2 is still running!");
  if ( exitCode1 != STILL_ACTIVE && exitCode2 != STILL_ACTIVE )
   break;
 }

 CloseHandle(hThrd1);
 CloseHandle(hThrd2);

 printf("Thread 1 returned %d\n", exitCode1);
 printf("Thread 2 returned %d\n", exitCode2);

 return EXIT_SUCCESS;
}

/*
* Take the startup value, do some simple math on it,
* and return the calculated value.
*/
DWORD WINAPI ThreadFunc(LPVOID n)
{
 Sleep((DWORD)n*1000*2);
 return (DWORD)n * 10;
}

  通过下面的程序我们可以看出多线程程序运行顺序的难以预料以及WINAPI的CreateThread函数与C运行时库的_beginthread的差别:

#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

DWORD WINAPI ThreadFunc(LPVOID);

int main()
{
 HANDLE hThrd;
 DWORD threadId;
 int i;

 for (i = 0; i < 5; i++)
 {
  hThrd = CreateThread(NULL, 0, ThreadFunc, (LPVOID)i, 0, &threadId);
  if (hThrd)
  {
   printf("Thread launched %d\n", i);
   CloseHandle(hThrd);
  }
 }
 // Wait for the threads to complete.
 Sleep(2000);

 return EXIT_SUCCESS;
}

DWORD WINAPI ThreadFunc(LPVOID n)
{
 int i;
 for (i = 0; i < 10; i++)
  printf("%d%d%d%d%d%d%d%d\n", n, n, n, n, n, n, n, n);
 return 0;
}

  运行的输出具有很大的随机性,这里摘取了几次结果的一部分(几乎每一次都不同):


  如果我们使用标准C库函数而不是多线程版的运行时库,则程序可能输出"3333444444"这样的结果,而使用多线程运行时库后,则可避免这一问题。

  下列程序在主线程中创建一个SecondThread,在SecondThread线程中通过自增对Counter计数到1000000,主线程一直等待其结束:

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

unsigned Counter;
unsigned __stdcall SecondThreadFunc(void *pArguments)
{
 printf("In second thread...\n");

 while (Counter < 1000000)
  Counter++;

 _endthreadex(0);
 return 0;
}

int main()
{
 HANDLE hThread;
 unsigned threadID;

 printf("Creating second thread...\n");

 // Create the second thread.
 hThread = (HANDLE)_beginthreadex(NULL, 0, &SecondThreadFunc, NULL, 0, &threadID);

 // Wait until second thread terminates
 WaitForSingleObject(hThread, INFINITE);
 printf("Counter should be 1000000; it is-> %d\n", Counter);
 // Destroy the thread object.
 CloseHandle(hThread);
}

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章