一、进程
进程是一个具有一定独立功能的程序在一个数据集合上一次动态执行的过程。
进程是一个正在运行的应用程序的实例,它由两部分组成:
(1)管理这个进程的操作系统的内核对象;(2)该进程拥有的地址空间。
每一个进程都有独占的、受到保护的32MB的地址空间。Windows CE系统最大允许32个独立的进程同时进行。
进程是应用程序的一个实例,其运行的目标就是执行它所对应的应用程序;进程是动态的,而程序是静态的。
同windows XP不同,Windows CE在创建进程的时候,最大只允许32个进程同时运行。当系统启动的时候,最少有4个默认的进程被启动,即:nk.exe(提供有关内核的服务);filesys.exe(提供有关文件系统的服务);gwes.exe(提供对GUI系统的支持);device.exe(装载和管理设备的驱动程序)
同windows XP不同,Windows CE中的进程一般包含较少的状态信息。
(1)不支持当前目录的概念;(2)不支持保存一系列的环境变量;(3)不支持句柄的继承。
一些函数:
1、创建进程
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结构的变量地址
CreatProcess函数在创建进程成功返回真值(TURE),失败则返回假值(FALSE)。如果返回值为假,可通过调用GetLastError函数来得到错误的信息。
LPPPROCESS_INFORMATION结构体的定义为:
Typedef struct _PROCESS_INFORMATION{
HANDLE hProcess;
HANDLE hThread;
HANDLE dwProcessID;
HANDLE dwThreadID;
}PROCESS_INFORMATION
结构中前两个参数hProcess和hThread分别为新创建进程的句柄和新创建进程中主线程的句柄。dwProcessID和dwThreadID则为进程的ID号和进程中主线程的ID号。
Unicode:一种文字编码,无论使用什么样的平台系统、什么样的程序或什么类型的语言,Unicode都为每个字符提供了一个唯一的数字标识。
2、创建进程
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文件。
终止一个进程时,我们需要知道相应进程的句柄,同时,在其他一些情况下,我们也需要知道一些进程的句柄。可以由以下函数来实现:
HANDLE OpenProcess(DWORD dwDesiredAccess, //Windows CE中设置为0
BOOL bInheritHandle, // Windows CE中设置为FALSE
DWORD dwProcessId) //表示想要打开进程的ID
在Windows CE系统中,我们也可以使用另一种函数来获得窗口的句柄,并得到相应进程的ID值。如:
GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId);
在Windows CE中,可以用一下函数直接读取一个进程的内存空间:
ReadProcessMemory(HANDLE hProcess, //进程的句柄
LPCVOID lpBaseAddress, //进程空间的基地址
LPVOID lpBuffer, //指定了将要读取数据的本地缓冲区的名称
DWORD nSize, //指定了将要读取数据的本地缓冲区的大小
LPDWORD lpNumberOfBytesRead); //指定了读取的字节数
如果想在Windows CE中直接写入一个进程的内存空间,则可以通过WriteProcessMemory函数:
WriteProcessMemory(HANDLE hProcess, //进程的句柄
LPCVOID lpBaseAddress, //进程空间的基地址
LPVOID lpBuffer, //将要写入数据的本地缓冲区的名称
DWORD nSize, //将要写入数据的本地缓冲区的大小
LPWORD lpNumberOfBytesWritten); //指定写入的字节数
二、线程
每一个进程都会分成许多的线程,与进程相比,真正的执行单元实际上是线程。
所谓线程,它实际上是进程的一个实体,是CPU调度和分配的基本单位。
除了一些在运行中必不可少的资源(如寄存器和栈等)外,线程本身并不占有系统的资源。但,线程却可以和同属于一个进程的另一个线程共享进程所拥有的全部资源。同进程一样,一个线程可以创建或者撤消另一个线程,同一个进程内的线程也可以并发执行。
每一个进程中都包含一个主线程,通过一定的函数,在一个进程中可以创建许许多多的线程,在Windows CE中创建线程的数量只受内存空间大小和线程栈空间大小的影响。进程中的线程会占用进程的地址空间,各个线程之间也拥有
Windows CE 3.0之后,系统支持的优先级增长到256个,0优先级级别最高,255优先级级别最低。0—247的优先级属于实时性优先级,248—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设备来说,对电力资源占用的大小是至关重要的。
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, //设置为0
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPWORD lpThreadID);
当参数dwCreationFlags被设置成STACK_SIZE_PARAM_IS_A_PESERVATION的时候,参数dwStackSize就可以指定初始化时栈的大小,此时Windows CE系统的内核将按照此参数设置的数值来保留栈的空间地址。
当参数dwCreationFlags没有被设置成STACK_SIZE_PARAM_IS_A_PESERVATION的时候,参数dwStackSize必须被设置成0,此时表示按照默认数值进行栈空间大小的设置。
当参数dwCreationFlags被设置成CREAT_SUSPENDED的时候,表示被创建的线程在创建以后一直处于挂起状态,知道ResumeThread函数将该线程恢复运行为止。
设置线程的优先级:
BOOL SetThreadPriority(HANDLE hThread,int nPriority);
BOOL CeSetThreadPriority(HANDLE hThread,int nPriority);
两者的区别:CeSetThreadPriority可以把线程设置成所有256个优先级中的任意一种,其中9代表优先级别最高,255代表优先级别最低。而函数SetThreadPriority只能设置成最基本的8个优先级别。同时,只有被信任的线程、安全级别很高的线程才能使用CeSetThreadPriority函数更改线程的优先级别。
查询线程的优先级别:
int GetThreadPriority(HANDLE hThread);
int CeGetThreadPriority(HANDLE hThread);
设置线程的时间片:
int CeSetThreadQuantum(HANDLE hThread,DWORD dwTime);
查询线程的时间片:
int CeSetThreadQuantum(HANDLE hThread);
挂起一个线程:
DWORD SuspendThread(HANDLE hThread);
在调用SuspendThread函数的时候,如果线程正在执行一个系统调用,那么挂起次线程就会失败。因此为了达到挂起线程的目的,可以多次调用SuspendThread函数,直到线程被挂起成功。
恢复一个线程:
DWORD ResumThread(HANDLE hThread);
三、进程间通信
Windows CE么提供消息、端口等复杂的通信机制,而是提供了用于等待队列的几种基本的通信手段。如,事件对象、互斥、临界区等。这些都被以系统对象的形式来实现。
所谓系统对象,就是由系统管理的资源实体,系统通过列表纪录并跟踪它们的状态。
1、事件对象
事件对象(Events)是同步对象之一,一个对象就类似一种特定的短消息,被用来通知每个线程发生了一个特定的事件。有的时候也会告诉这个线程应该做什么事情。
事件对象具备有信号(signaled)和无信号(nonsignaled)两种状态。事件对象在创建的时候可以选择自动的从signaled状态恢复到nonsignaled状态,或者手动恢复到这个状态。事件对象是可以被用于共享进程间的同步通信的。
创建事件对象:
HANDLE CreatEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, //设置为NULL
BOOL bManualReset, //表示是否手动设置事件对象的状态
BOOL bInitialState, //表示事件对象初始化的时候是否被设置成有信号状态或者无信号状态
LPTSTR lpName); //事件对象的名字
如果我们想在进程之间共享一个事件对象,那么就需要在每一个进程里面创建一个事件对象,而不能只在一个里面创建后把事件对象的句柄传递给另一个进程。
BOOL SetEvent(HANDLE hEvent); //将事件对象设置为有信号状态
BOOL PulseEvent(HANDLE hEvent); //将事件对象设置成有信号状态
BOOL ResetEvent(HANDLE hEvent); //手动地把事件对象设置成无信号状态
2、线程等待
DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMillisecongs);
函数仅当在参数列表中指定的对象处于信号态或超过了超时间间隔,该函数才返回。hHandle为标识的同步对象,起等待的时间为dwMilliseconds指定的值,等待间的单位为毫秒。当我们给参数dwMilliseconds传递的值为INFINITE的时候,表示该对象将无限期的等待下去。
DWORD WaitForMultipleObjects(DWORD nCount,CONST HANDLE *lpHandles,
BOOL fWaitAll,DWORD dwMilliseconds);
这个函数返回的是同步对象在数组中的索引。
DWORD MsgWaitForMultipleObjects(DWORD nCount,LPHANDLE lpHandles,
BOOL fWaitAll,DWORD dwMilliseconds,
DWORD dwWakeMask);
这个函数的功能同WaitForMultipleObjects函数类似,只是增加了一个和消息相关的,被称为唤醒掩码(dwWakeMask)的参数。这个函数不但能够等待内核对象,还可以等待指定的消息。
DWORD MsgWaitForMultipleObjectsEx(DWORD nCount,LPHANDLE lpHandles,
BOOL fWaitAll,DWORD dwMilliseconds,
DWORD dwWakeMask);
这个函数实际上是MsgWaitForMultipleObjects的扩展,如果一个线程在执行大量任务的同时还要响应用户的按键消息。MsgWaitForMultipleObjects和MsgWaitForMultipleObjectsEx将会起到很大的作用。
3、信号量
信号量机制是一种非常有效的进程同步机制,它已经被广泛地应用于各种类型的操作系统中。
在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函数释放信号量,以使当前可用资源数递增。同时在Windows CE下,系统不支持OpenSemaphore函数。
4、互斥
互斥也是一种保证线程同步的手段之一,它能够保证多个线程对同一共享资源的互斥访问。只有拥有互斥对象的线程才具有访问资源的权限。同时,由于互斥对象只有一个,因此就决定了了任何情况下共享资源都不会同时被多个线程所访问。
创建一个互斥对象:
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, //设置成NULL
BOOL bInitialOwner, //TURE或者FALSE
LPCTSTR lpName); //互斥对象的名称
当互斥对象被创建以后,如果我们想获得这个互斥对象,首先应该通过GetLastError函数来验证互斥资源是否已经被提交,如果已经被前一个使用它的线程提交,那么我们就可以通过WaitForSingleObject函数来获得这个互斥对象。
释放一个掉一个互斥对象:
BOOL ReleaseMutex(HANDLE bMutex);
Windows CE中不支持OpenMutex函数。
5、互锁函数
在Windows CE中,互锁函数的作用是保证当一个线程访问一个变量的时候,其他线程无法访问此变量,以确保变量值的唯一性,这种访问方式称之为原子访问。
Windows CE支持完整的互锁Win32API函数。
LONG InterlockedIncrement(LPLONG lpAddend);
这个函数使一个LONG类型的变量增加1,里面的参数为指向这个变化变量的指针。
LONG InterlockedDncrement(LPLONG lpAddend);
这个函数使一个LONG类型的变量减少1,里面的参数为指向这个变化变量的指针。
LONG InterlockedExchange(LPLONG Target,LONG Value);
这个函数的作用是将参数Value的值赋给Target指向的值,函数将返回参数Target指向变量的初始值。
LONG InterlockedCompareExchange(LPLONG Destination,
LONG Exchange,
LONG Comperand);
这个函数的作用是将参数Destination指向的值和参数Comperand的值进行比较,如果这两个值相同,则把参数Exchange的值赋给参数Destination指向的值;如果不相同,则不变。函数返回的是参数1指向的变量的初始值。
LONG InterlockedTestExchange(LPLONG target,LONG OldValue,LONG NewValue);
这个函数的作用是将参数target指向的值和OldValue的值进行比较,如果这两个值相同,则把参数NewValue的值赋给target指向的值;如果不相同,则不作变化。
LONG InterlockedTestExchangeAdd(LPLONG Addend,LONG Increment);
这个函数的作用是将参数Increment的值加到参数Addend指向的值中,函数返回的是参数Addend指向变量的初始值。
LONG InterlockedCompareExchangePointer(PVOID *Destination,PVOID Exchange,
PVOID Comperand);
这个函数的作用和函数InterlockedCompareExchange相同,只不过传递的数据都是指针类型的。函数的返回值为参数1指向指针的初始值。
LONG InterlockedExchangePointer(PVOID *Targe,PVOID Value);
这个函数的作用是同函数InterlockedExchange相同,只不过传递的数据是指针类型。函数的返回值为指针1指向指针的初始值。
6、临界区
临界区是Windows CE系统内部最常用的互斥手段,它能保证在临界区内所有被访问的资源不被其他线程访问,直到当前线程执行完临界区的代码为止。一般情况下,临界区对象用于保证一段程序代码的不间断性,一个临界区对象的使用通常被限定在某一个进程或者动态链接库中。
与临界区相关的函数主要有:
void InitializeCriticalSection(LPCRITICAL_SECTION);
函数InitializeCriticalSection的作用是初始化临界区;
void EnterCriticalSection(LPCRITICAL_SECTION);
函数EnterCriticalSection的作用是进入临界区;
void LeaveCriticalSection(LPCRITICAL_SECTION);
函数LeaveCriticalSection的作用是退出临界区;
void DeleteCriticalSection(LPCRITICAL_SECTION);
函数DeleteCriticalSection的作用是撤销临界区;
void TryEnterCriticalSection(LPCRITICAL_SECTION);
函数TryEnterCriticalSection的作用是尝试进入临界区。