现在的位置: 首页 > 综合 > 正文

线程基础知识

2013年10月27日 ⁄ 综合 ⁄ 共 3266字 ⁄ 字号 评论关闭

设置方法:
BOOL SetPriorityClass( HANDLE hProcess, DWORD dwPriority );
DWORD GetPriorityClass( HANDLE hProcess );
使用命令外壳启动一个程序时,该程序的起始优先级是正常优先级。如果使用Start命令来启动该程序,可以使用一个开关来设定应用程序的起始优先级。例如:
c:/>START /LOW CALC.EXE
Start命令还能识别/BELOWNORMAL、/NORMAL、/ABOVENORMAL、/HIGH和/REALTIME等开关。

7. 线程的相对优先级有哪些?
相对优先级 标识符 描述
关键时间    THREAD_PRIORITY_TIME_CRITICAL 对于实时优先级类线程在优先级31上运行,对于其他优先级类,线程在优先级15上运行。
最高    THREAD_PRIORITY_HIGHEST 线程在高于正常优先级上两级上运行。
高于正常    THREAD_PRIORITY_ABOVE_NORMAL 线程在正常优先级上一级上运行。
正常    THREAD_PRIORITY_NORMAL 线程在进程的优先级类上正常运行。
低于正常    THREAD_PRIORITY_BELOW_NORMAL 线程在低于正常优先级下一级上运行。
最低    THREAD_PRIORITY_LOWEST 线程在低于正常优先级下两级上运行。
空闲    THREAD_PRIORITY_IDLE 对于实时优先级类线程在优先级16上运行对于其他优先级类线程在优先级1上运行。
设置方法:
BOOL SetThreadPriority( HANDLE hThread, DWORD dwPriority );
DWORD GetThreadPriorityClass( HANDLE hThread );

8. 如何避免系统动态提高线程的优先级等级?
       
系统常常要提高线程的优先级等级,以便对窗口消息或读取磁盘等I/O事件作出响应。或者当系统发现一个线程在大约3至4s内一直渴望得到CPU时间,它就
将这个渴望得到CPU时间的线程的优先级动态提高到15,并让该线程运行两倍于它的时间量。当到了两倍时间量的时候,该线程的优先级立即返回到它的基本优
先级。下面的函数可以对系统的调度方式进行设置:
BOOL SetProcessPriorityBoost( HANDLE hProcess, BOOL bDisableBoost );
BOOL GetProcessPriorityBoost( HANDLE hProcess, PBOOL pbDisableBoost );
BOOL SetThreadPriorityBoost( HANDLE hThread, BOOL bDisableBoost );
BOOL GetThreadPriorityBoost( HANDLE hThread, PBOOL pbDisableBoost );
SetProcessPriorityBoost负责告诉系统激活或停用进行中的所有线程的优先级提高功能,而SetThreadPriorityBoost则激活或停用各个线程的优先级提高功能。Windows98没有提供这4个函数的有用的实现代码。

用户方式中线程的同步
1. 仅一条语句用不用考虑线程同步的问题?

使用高级语言编程时,我们往往会认为一条语句是最小的原子访问,CPU不会在这条语句中间运行其他的线程。这是错误的,因为即使非常简单的一条高级语言的
语句,经编译器编译后也可能变成多行代码由计算机来执行。因此必须考虑线程同步的问题。任何线程都不应该通过调用简单的C语句来修改共享的变量。

2. 互锁函数有那些?
(1) LONG InterlockedExchangeAdd ( LPLONG Addend, LONG Increment );
Addend为长整型变量的地址,Increment为想要在Addend指向的长整型变量上增加的数值(可以是负数)。这个函数的主要作用是保证这个加操作为一个原子访问。
(2) LONG InterlockedExchange( LPLONG Target, LONG Value );
用第二个参数的值取代第一个参数指向的值。函数返回值为原始值。
(3) PVOID InterlockedExchangePointer( PVOID *Target, PVOID Value );
用第二个参数的值取代第一个参数指向的值。函数返回值为原始值。
(4) LONG InterlockedCompareExchange(
LPLONG Destination, LONG Exchange, LONG Comperand  );
如果第三个参数与第一个参数指向的值相同,那么用第二个参数取代第一个参数指向的值。函数返回值为原始值。
(5) PVOID InterlockedCompareExchangePointer (
PVOID *Destination, PVOID Exchange, PVOID Comperand );
如果第三个参数与第一个参数指向的值相同,那么用第二个参数取代第一个参数指向的值。函数返回值为原始值。

3. 为什么单CPU的计算机不应该使用循环锁?
举例说明:
BOOL g_bResourceUse = FALSE;
……
void ThreadFunc1(  )
{
 BOOL bResourceUse = FALSE;
 while( 1 )
{
 bResourceUse = InterlockedExchange( &g_bResourceUse, TRUE );
 if( bResourceUse == FALSE )
 {
  break;
 }
 Sleep( 0 );
}
……
……
……
InterlockedExchange( &g_bResourceUse, FALSE );
}

先循环锁会浪费CPU时间。CPU必须不断地比较两个值,直到一个值由于另一个线程而“奇妙地”改变为止。而且使用该循环锁的线程都应该为同一优先级,并
且应当使用SetProcessPriorityBoost函数或SetThreadPriorityBoost函数禁止线程优先级的动态提高功能,否则
优先级较低的线程可能永远不能被调用。

4. 如何使用volatile声明变量?
如果是对共享资源的地址进行使用如&
g_Resource那么可以不使用volatile,因为将一个变量地址传递给一个函数时,该函数必须从内存读取该值。优化程序不会对它产生任何影响。
如果直接使用变量,必须有一个volatile类型的限定词。它告诉编译器,变量可以被应用程序本身以外的某个东西进行修改,这些东西包括操作系统,硬件
或同时执行的线程等。volatile限定词会告诉编译器,不要对该变量进行任何优化,并且总是重新加载来自该变量的内存单元的值。否则编译器会把变量的
值存入CPU寄存器,每次对寄存器进行操作。线程就会进入一个无限循环,永远无法唤醒。

5. 如何使用关键代码段实现线程的同步?

果需要一小段代码以原子操作的方式执行,这时简单的互锁函数已不能满足需要,必须使用关键代码段来解决问题。不过使用关键代码段时,很容易陷入死锁状态,
因为在等待进入关键代码段时无法设定超时值。关键代码段是通过对共享资源设置一个标志来实现的,就像厕所门上的“有人/没人”标志一样。这个标志就是一个
CRITICAL_SECTION变量。该变量在任何一个线程使用它之前应当进行初始化。初始化可以有两种方法,使用
InitializeCriticalSection函数和InitializeCriticalSectionAndSpinCount函数。然后在每
个使用共享资源的线程函数的关键代码段前使用EnterCriticalSection函数或者使用TryEnterCriticalSection函
数。在关键代码段使用之后调用LeaveCriticalSection函数。在所有的线程都不再使用该共享资源后应当调用
DeleteCriticalSection函数来清除该标志。

【上篇】
【下篇】

抱歉!评论已关闭.