Windows CE中的进程和线程
(1)进程
进程是一个正在运行的应用程序的实例,它由两部分组成:A,管理这个进程的操作系统的内核对象;B,该进程拥有的地址空间。每一个进程都有独占的、受到保护的32MB的地址空间。Windows CE系统最大允许32个独立的进程同时进行。当系统启动的时候,最少有4个默认的进程被启动,即:nk.exe(提供有关内核的服务);filesys.exe(提供有关文件系统的服务);gwes.exe(提供对GUI系统的支持);device.exe(装载和管理设备的驱动程序)。以下是一系列函数:
A,创建进程
BOOL CreatProcess(LPCTSTR lpApplicationName,
LPCTSTR lpCommandLine,
LPSECURITY_ATTRIBUSTES lpProcessAttributes,
LPSECURITY_ARRTIBUSTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnviromment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPPROCESS_INFORMATION lpProcessInformation);
因为Windows CE不支持安全性、继承性和当前目录,所以这个API很多参数都必须设置成0或者False,即:
BOOL CreatProcess(LPCTSTR lpApplicationName, //应用程序的名称
LPCTSTR lpCommandLine, //用于传递启动参数,只能是Unicode
NULL,NULL,FALSE,
DWORD dwCreationFlags, //进程的状态标志
NULL,NULL,NULL,
LPPPROCESS_INFORMATION lpProcessInformation);//传递一个LPPPROCESS_INFORMATION结构的变量地址
其中,LPPPROCESS_INFORMATION结构体的定义为:
Typedef struct _PROCESS_INFORMATION{
HANDLE hProcess;
HANDLE hThread;
HANDLE dwProcessID;
HANDLE dwThreadID;
}PROCESS_INFORMATION
结构中前两个参数hProcess和hThread分别为新创建进程的句柄和新创建进程中主线程的句柄。dwProcessID和dwThreadID则为进程的ID号和进程中主线程的ID号。
B,退出进程
VOID ExitProcess(UINT uExitCode);uExitCode为退出代码。这个函数能彻底地实现进程的关闭功能,即,它将把进程终止的消息通知所有和该进程关联的动态链接库(DLL)。可以通过下面的函数来获得指定进程的退出代码:
BOOL GetExitCodeProcess(HANDLE hProcess,LPDWORD lpExitCode);
一个进程处于运行状态的时候,其退出代码为STILI_ACTIVE。当一个进程被成功终止的时候,其终止状态可能是下面的三种:
1,ExitProcess或者TerminateProcess函数指定的退出代码;2,mian或者WinMain函数中的返回值;3,引起进程异常终止的代码。
如果想在当前进程中终止另一个进程,则可以使用下面的函数:
BOOL TerminateProcess(HANDLE hProcess,DWORD uExitCode);hProcess为句柄;uExitCode为退出代码。
需要注意的是,使用TerminateProcess函数会无条件的终止相关进程,该进程中的所有线程也会被终止。同时,还会把进程终止的消息同时给和这个进程有关的DLL文件。
C,获得进程ID
终止一个进程时,我们需要知道相应进程的句柄,同时在其他一些情况下,我们也需要知道一些进程的句柄。可以由以下函数来实现:
HANDLE OpenProcess(DWORD dwDesiredAccess, //Windows CE中设置为0
BOOL bInheritHandle, // Windows CE中设置为FALSE
DWORD dwProcessId) //表示想要打开进程的ID
在Windows CE系统中,我们也可以使用另一种函数来获得窗口的句柄,并得到相应进程的ID值。如:
GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId);
(2)线程
除了一些在运行中必不可少的资源(如寄存器和栈等)外,线程本身并不占有系统的资源。但线程却可以和同属于一个进程的另一个线程共享进程所拥有的全部资源。同进程一样,一个线程可以创建或者撤消另一个线程,同一个进程内的线程也可以并发执行。
每一个进程中都包含一个主线程,通过一定的函数,在一个进程中可以创建许许多多的线程,在Windows CE中创建线程的数量只受内存空间大小和线程栈空间大小的影响。Windows CE 3.0之后,系统支持的优先级增长到256个,0优先级级别最高,255优先级级别最低。其中:
0—96:优先级高于驱动程序的程序;
97—152:基于Windows CE.Net的驱动程序;
153—247:优先级低于驱动程序的程序;
248—255:普通的应用程序。
在Windows CE中,线程一般分为5个状态,分别为运行状态(running)、挂起(suspended)、睡眠(sleeping)、阻塞(blocking)、终止(terminated)。其中,当系统内所有的线程处于阻塞状态的时候,系统的内核则处于空闲模式(Idle Model),此时对CPU的电力资源的占用将减少。要知道,对于大多数靠电池供应电力的Windows CE设备来说,对电力资源占用的大小是至关重要的。一下是一系列函数:
A,设置线程的优先级:
BOOL CeSetThreadPriority(HANDLE hThread,int nPriority);
B,查询线程的优先级别:
int CeGetThreadPriority(HANDLE hThread);
(3)进程间通信
Windows CE没提供消息、端口等复杂的通信机制,而是提供了用于等待队列的几种基本的通信手段。如,事件对象、互斥、临界区等。这些都被以系统对象的形式来实现。所谓系统对象,就是由系统管理的资源实体,系统通过列表纪录并跟踪它们的状态。
A,信号量
在Windows CE中,当线程在等待信号量的时候,该线程处于锁住(blocked)状态,这种状态一直持续到可用资源大于0为止。可用资源的最大值是在创建信号量的时候被指定的,因此我们可以通过信号量来指定访问资源的线程的数量。
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, //NULL
LONG lInitialCount, //当前可用资源的初始值
LONG lMaximumCount, //最大可用资源数量
LPCTSTR lpName); //对象的名字
当线程访问完可用资源以后,将释放信号量。释放信号量的函数为:
BOOL ReleaseSemaphor(HANDLE hSemaphore, //对象的句柄
LONG lReleaseCount, //要释放的资源数
LPLONG lpPreviousCount); //返回原来的可用资源数
当一个线程访问完可用资源以后,必须使用ReleaseSemaphor函数释放信号量,以使当前可用资源数递增。
B,互斥
互斥也是一种保证线程同步的手段之一,它能够保证多个线程对同一共享资源的互斥访问。只有拥有互斥对象的线程才具有访问资源的权限。同时,由于互斥对象只有一个,因此就决定了了任何情况下共享资源都不会同时被多个线程所访问。创建一个互斥对象:
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, //设置成NULL
BOOL bInitialOwner, //TURE或者FALSE
LPCTSTR lpName); //互斥对象的名称
当互斥对象被创建以后,如果我们想获得这个互斥对象,首先应该通过GetLastError函数来验证互斥资源是否已经被提交,如果已经被前一个使用它的线程提交,那么我们就可以通过WaitForSingleObject函数来获得这个互斥对象。释放一个互斥对象:
BOOL ReleaseMutex(HANDLE bMutex);
C,互锁函数
在Windows CE中,互锁函数的作用是保证当一个线程访问一个变量的时候,其他线程无法访问此变量,以确保变量值的唯一性,这种访问方式称之为原子访问。Windows CE支持完整的互锁Win32API函数。
LONG InterlockedIncrement(LPLONG lpAddend);
这个函数使一个LONG类型的变量增加1,里面的参数为指向这个变化变量的指针。
LONG InterlockedDncrement(LPLONG lpAddend);
这个函数使一个LONG类型的变量减少1,里面的参数为指向这个变化变量的指针。
D,临界区
临界区是Windows CE系统内部最常用的互斥手段,它能保证在临界区内所有被访问的资源不被其他线程访问,直到当前线程执行完临界区的代码为止。一般情况下,临界区对象用于保证一段程序代码的不间断性,一个临界区对象的使用通常被限定在某一个进程或者动态链接库中。与临界区相关的函数主要有:
void InitializeCriticalSection(LPCRITICAL_SECTION);函数InitializeCriticalSection的作用是初始化临界区;
void EnterCriticalSection(LPCRITICAL_SECTION);函数EnterCriticalSection的作用是进入临界区;
void LeaveCriticalSection(LPCRITICAL_SECTION);函数LeaveCriticalSection的作用是退出临界区;
void DeleteCriticalSection(LPCRITICAL_SECTION);函数DeleteCriticalSection的作用是撤销临界区;