当前位置:首页 > 14-15(2)实验指导书
问权限;dwExitCode定义调用线程的退出代码。
返回值:若函数调用成功则返回TRUE,否则返回FALSE。
五、 线程的同步
多线程编程中关键的一步是保护所有的共享资源状态的一致性,线程同步工具主要有事件对象、互斥体、信号量等。
1.事件
在进程内或进程间实现线程同步的最简单的方法是使用事件对象,这个事件对象可允许线程直接控制其信号状态(见表2-1)。内核事件对象是人工对同一进程或其他进程中的线程进行广播的一个简单方法。
事件的使用很简单。用CreateEvent()API创建一个事件并返回事件句柄。事件分为人工复位和自动复位,可使用SetEvent()API把人工复位事件改变为有信号状态,也可使用ResetEvent()API使人工复位事件变为无信号状态。使用PulseEvent()API可将自动重置事件转化为有信号状态,此函数释放所有等待的线程之后,使事件又转化为无信号状态。
当另一个进程需要访问事件对象时,可共享事件对象句柄。这时该进程必须使用事件名称,调用OpenEvent()API,创建引用。当事件对象不再被引用时,需要使用CloseHandle()API关闭所有对象事件的引用,之后事件不再存在。
相关API函数说明如下: (1)CreateEvent
函数功能:该函数用来创建一个命名或未命名的事件对象。 函数格式:
HANDLE CreateEvent(
LPSECURITYATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL blnitialState, LPCTSTR lpName);
表2-1 用于管理事件对象的API API名称 CreateEvent() 描 述 在内核中创建一个新的事件对象。此函数允许有名称规范、安全性设置、用于人工还是自动重置的标志以及表明初始状态为有信号还是无信号状态 打开已经存在的事件对象。此API函数需要事件名称、继承标志和所需的访问级别 将人工重置事件转化为有信号状态 将人工重置事件转化为无信号状态 将自动重置事件对象转化为有信号状态。当系统释放所有的等待它的线程时此种转化立即发生 OpenEvent() SetEvent() ResetEvent() PulseEvent()
参数:
·lpEVentAttributes指定一个结构,用于设置新事件对象的安全属性,包括访问 权和继承权等。
·bManualReset如果参数为TRUE,函数将创建一个人工重置事件;如果参数为 FALSE,表示创建一个自动重置事件。
·bInitialState如果参数为TRUE,则事件为初始状态有信号,否则无信号。
·lpName指定事件对象名称。
返回值:如果执行成功,返回事件对象的句柄,否则返回值为0。 (2)OpenEvent
函数功能:该函数用来打开一个已命名的事件对象,以获得该对象的句柄。 函数格式:
HANDLE OpenEvent(
DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName); 参数: · dwDesiredAccess 指定事件对象的访问形式,可以是下列参数的一个或几个的组合: EVENT_ALL_ACCESS 为事件对象指定所有可能的访问权限标志。
EVENT_MODIFY_STATE 在SetEvent和ResetEvent函数中启动事件句柄的使用,以更改事件的状态。
SYNCHRONIZE 允许启用在任何等待函数中的事件句柄,等待事件的状态成为有信号态。
·BInheritHandle 指定的继承标志。若句柄可以由子进程继承,则设置为TRUE,否则设置为FALSE。
·LpName指向包括事件对象名的字符串的指针。
返回值:如果函数执行成功,返回事件对象的句柄,否则返回值为FALSE。 备注:此函数可以在多个线程中为同一个事件对象打开句柄,但此事件对象必须是用函数CreateEvent创建的。当不再需要句柄时,可以用函数CloseHandle来关闭句柄。
(3)SetEvent 函数功能:该函数用于将事件对象的状态改为有信号状态。有信号的事件将允许线程等待,以便事件继续执行。
函数格式:
BOOL SetEvent(HANDLE hEvent);
参数:hEvent指定要改变为有信号态的事件对象的句柄。 返回值:如果函数执行成功则返回TRUE,否则返回FALSE。 (4)ResetEvent 函数功能:该函数用于将事件对象的状态改为无信号状态。一个处于无信号态的事件将阻塞所有等待线程。
函数格式:
BOOL ResetEvent(HANDLE hEvent);
参数:hEvent指定要改变为无信号态的事件对象的句柄。 返回值:如果函数执行成功则返回TRUE,否则返回FALSE。 (5)PulseEvent 函数功能:该函数将自动重置事件对象转化为有信号状态。当系统释放所有的等待事件对象的线程时,此种转化立即发生。
函数格式:
BOOL PulseEvent(HANDLE hEvent);
参数:hEyent指定等待得到信号的事件对象的句柄。该事件必须拥有EVENT_MODIFY_STATE的访问权限。
返回值:如果函数执行成功则返回TRUE,否则返回FALSE。
备注:该函数对于人工复位事件对象,释放所有可以立即释放的等待线程;对于自动复位事件对象,则只是释放一个等待线程,而不管其他的等待线程。若没有线程可以释放,则将事件对象设置为无信号态后再返回。
为了更好地掌握事件对象的使用,下面举一个例子来实现进程间的通信。 例3-4: 创建和打开进程间的要发送信号的事件对象。 #include
// 以下是句柄事件。实际中很可能使用共享的包含文件来进行通信
static LPCTSTR g_szContinueEvent=\.EventDemo.event.Continue\// 这个方法只是创建了一个进程的副本 BOOL CreateChild() {
TCHAR szFilename[MAX_PATH]; // 提取当前可执行文件的文件名
GetModuleFileName(NULL,szFilename,MAX_PATH);
//格式化用于子进程的命令行,指明是一个EXE文件和子进程 TCHAR szCmdLine[MAX_PATH];
sprintf(szCmdLine,\ STARTUPINFO si; // 子进程的启动信息结构
ZeroMemory(reinterpret_cast
PROCESS_INFORMATION pi; //返回的子进程的进程信息结构 //用同样的可执行文件和命令行创建进程 BOOL bCreateOK=CreateProcess(
szFilename, //可执行的应用程序的名称
szCmdLine, //指定创建一个子进程的符号标识 NULL, //默认的进程安全性 NULL, //默认的线程安全性 FALSE, //不继承句柄 0, //特殊的创建标志 NULL, //新环境 NULL, //当前目录 &si, //启动信息结构
&pi); //返回进程和线程信息 // 运行结束,关闭进程和其线程的句柄 if(bCreateOK) {
CloseHandle(pi.hProcess); CloseHandle(pi.hThread); }
return(bCreateOK); }
// 下面的方法创建一个事件和一个子进程,然后等待子进程在返回前向事件发出信号 void WaitForChild( )
{
// 创建事件和子进程,然后等待子进程给事件发送信号 HANDLE hEventContinue=CreateEvent(
NULL, // 默认的安全性,子进程将具有访问权限 TRUE, // 人工重置事件
FALSE, // 初始时是无信号状态 g_szContinueEvent); // 事件名称 if(hEventContinue!=NULL) {
printf(\.\\n\ //创建子进程
if(CreateChild()) {
printf(\.\\n\
printf(\.\\n\\n\ // 等待,直到子进程将事件置为有信号状态
WaitForSingleObject(hEventContinue,INFINITE);
printf(\process.\\n\
}
//句柄
CloseHandle(hEventContinue); } }
//以下方法在子进程模式下被调用,其功能只是向父进程发出终止信号 void SignalParent() {
//打开句柄
HANDLE hEventContinue=OpenEvent(
EVENT_MODIFY_STATE, //所要求的最小访问权限 FALSE, //不是可继承的句柄
g_szContinueEvent); //事件名称 if(hEventContinue!=NULL) {
printf(\\\n\
printf(\ getchar();
SetEvent(hEventContinue); }
CloseHandle(hEventContinue) ;//清除句柄 }
int main(int argc,char *argv[]) {
// 检查父进程或子进程是否启动
共分享92篇相关文档