《windows核心编程学习笔记》——使用互斥量变量内核对象进行线程同步
2011-09-08 20:27
465 查看
用途:互斥量内核对象用来确保一个线程独占对一个资源的访问。
用法:
如多个线程需要对同一内存进行读写操作。大致操作如下:
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL); //创建一个互斥量
T Read()
{
WaitForSingleObject(hMutex, INFINITE);
//read the buffer
ReleaseMutex(hMutex);
}
void Write(T data)
{
WaitForSingleObject(hMutex, INFINITE);
//write the buffer
ReleaseMutex();
}
理解:
创建一个互斥量用于线程同步,互斥量对象包含一个使用计数,线程ID及一个递归计数。线程ID用来标识当前占用这个互斥量的是系统的哪个线程,递归计数标识这个线程占用改互斥量的次数。CreateMutex的第二个参数指定了互斥量内核对象初始创建时的状态(TRUE 未触发,FALSE已触发),其他参数参见MSDN。假设当前有两个线程,一个进行操作,一个进行读操作。
假设写线程第一次执行Write操作,调用等待函数WaitForSingleObject, 传入互斥量句柄。在内部,等待函数会检查互斥量线程ID是否为0(互斥量处于触发状态)。如果为0,那么函数会把线程ID设为条用线程的线程ID,把递归计数设为1,然后让调用线程继续运行。需要说明的是WaitForSingleObject 函数使一个线程自愿进入等待状态,直到指定的内核对象被触发为止。但是,如果线程在调用一个等待函数的时候,相应的内核对象已经处于触发状态,那么线程是不会进入等待状态的。也就是说等待函数等待的是内核对象状态瞬间的变化(由未触发变为已触发),而不是等待变化完的状态。如果上面的例子中创建互斥量的时候,第二个参数传入的是TRUE,也就是初始状态是未触发的,那么除非我们明确的调用函数使内核状态变为触发状态,否则读写线程永远也不会捕捉到内核状态的变化,这样就会出现永远等待的情况。
回到刚才的情况,写线程正在执行写操作,互斥量内核对象的线程ID记录这当前占有这个互斥量的线程ID。此时,读线程执行Read操作,调用等待函数,等待函数检查互斥量线程ID,发现ID不为0,读线程进入等待状态。 当写线程完成写操作之后,调用ReleaseMutex。 在内部,这个函数会将互斥量内核对象的递归计数减1,当递归计数变成0的时候,函数还会将线程ID设为0,这样就触发了内核对象。当对象被触发的时候,系统会检查有没有其他的线程正在等待该互斥量,如果有系统会“公平地”选择一个正在等待的线程,把互斥量的所有权给它,同样,内核对象把线程ID设为占有互斥量的那个线程ID,递归计数设为1。上例中,此时的读线程就有机会读内存了。如果没有线程等待,那么互斥量会保持在触发状态,这样下一个等待它的线程就可以立即进入互斥区域了。
注意:
(1)假设线程试图等待一个未触发的内核对象,线程通常会进入等待状态。但对于互斥量内核对象却不一定如此,如果此时线程ID和互斥量内部线程ID一致,那么线程会保持可调度状态,即使互斥量处于未触发状态。简单点说就是在当前线程拥有互斥区的时候又调用WaitForSingleObject。这也是是递归计数大于1的唯一途径。如果多次成功等待了互斥量,也必须调用相应次数的ReleaseMutex函数使互斥量处于触发状态。
(2)线程是否互斥量的时候,线程ID如果与互斥量内部ID一致,递归计数减1。如果不一致,则ReleaseMutex会返回FALSE给调用者,指示调用失败。如果释放互斥量的线程已经终止,系统会认为互斥量已被“遗弃”。这是系统会自动将互斥量线程ID设为0,递归计数设为0,互斥量处于已触发状态。
用法:
如多个线程需要对同一内存进行读写操作。大致操作如下:
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL); //创建一个互斥量
T Read()
{
WaitForSingleObject(hMutex, INFINITE);
//read the buffer
ReleaseMutex(hMutex);
}
void Write(T data)
{
WaitForSingleObject(hMutex, INFINITE);
//write the buffer
ReleaseMutex();
}
理解:
创建一个互斥量用于线程同步,互斥量对象包含一个使用计数,线程ID及一个递归计数。线程ID用来标识当前占用这个互斥量的是系统的哪个线程,递归计数标识这个线程占用改互斥量的次数。CreateMutex的第二个参数指定了互斥量内核对象初始创建时的状态(TRUE 未触发,FALSE已触发),其他参数参见MSDN。假设当前有两个线程,一个进行操作,一个进行读操作。
假设写线程第一次执行Write操作,调用等待函数WaitForSingleObject, 传入互斥量句柄。在内部,等待函数会检查互斥量线程ID是否为0(互斥量处于触发状态)。如果为0,那么函数会把线程ID设为条用线程的线程ID,把递归计数设为1,然后让调用线程继续运行。需要说明的是WaitForSingleObject 函数使一个线程自愿进入等待状态,直到指定的内核对象被触发为止。但是,如果线程在调用一个等待函数的时候,相应的内核对象已经处于触发状态,那么线程是不会进入等待状态的。也就是说等待函数等待的是内核对象状态瞬间的变化(由未触发变为已触发),而不是等待变化完的状态。如果上面的例子中创建互斥量的时候,第二个参数传入的是TRUE,也就是初始状态是未触发的,那么除非我们明确的调用函数使内核状态变为触发状态,否则读写线程永远也不会捕捉到内核状态的变化,这样就会出现永远等待的情况。
回到刚才的情况,写线程正在执行写操作,互斥量内核对象的线程ID记录这当前占有这个互斥量的线程ID。此时,读线程执行Read操作,调用等待函数,等待函数检查互斥量线程ID,发现ID不为0,读线程进入等待状态。 当写线程完成写操作之后,调用ReleaseMutex。 在内部,这个函数会将互斥量内核对象的递归计数减1,当递归计数变成0的时候,函数还会将线程ID设为0,这样就触发了内核对象。当对象被触发的时候,系统会检查有没有其他的线程正在等待该互斥量,如果有系统会“公平地”选择一个正在等待的线程,把互斥量的所有权给它,同样,内核对象把线程ID设为占有互斥量的那个线程ID,递归计数设为1。上例中,此时的读线程就有机会读内存了。如果没有线程等待,那么互斥量会保持在触发状态,这样下一个等待它的线程就可以立即进入互斥区域了。
注意:
(1)假设线程试图等待一个未触发的内核对象,线程通常会进入等待状态。但对于互斥量内核对象却不一定如此,如果此时线程ID和互斥量内部线程ID一致,那么线程会保持可调度状态,即使互斥量处于未触发状态。简单点说就是在当前线程拥有互斥区的时候又调用WaitForSingleObject。这也是是递归计数大于1的唯一途径。如果多次成功等待了互斥量,也必须调用相应次数的ReleaseMutex函数使互斥量处于触发状态。
(2)线程是否互斥量的时候,线程ID如果与互斥量内部ID一致,递归计数减1。如果不一致,则ReleaseMutex会返回FALSE给调用者,指示调用失败。如果释放互斥量的线程已经终止,系统会认为互斥量已被“遗弃”。这是系统会自动将互斥量线程ID设为0,递归计数设为0,互斥量处于已触发状态。
相关文章推荐
- Windows核心编程笔记(九)使用内核对象进行线程同步
- 用内核对象进行线程同步——互斥量内核对象
- 第九章 使用内核对象进行线程同步
- 第9章 用内核对象进行线程同步(1)_事件对象(Event)
- windows核心编程-用内核对象进行线程同步
- 第九章:用内核对象进行线程同步(二) .
- 第9章 用内核对象进行线程同步(4)_死锁(DeadLock)及其他
- 线程同步 互斥量 Mutex 内核对象 CreateMutex
- windows 用内核对象进行线程同步
- 《Windows核心编程》——九 用内核对象进行线程同步
- Windows核心编程学习九:利用内核对象进行线程同步
- 线程的创建、管理 与 使用信号灯、互斥量、临界区、事件进行线程同步或互斥
- KVC的使用(对一个对象的成员变量进行操作(赋值/取值))
- 第九章:用内核对象进行线程同步(一)
- Windows-核心编程-09-如何用内核对象进行线程同步-事件内核对象
- Windows核心编程--用内核对象进行线程同步(一)
- 《Windows核心编程 5th》读书笔记----第9章 用内核对象进行线程同步
- 第9章 用内核对象进行线程同步(3)_信号量(semaphore)、互斥对象(mutex)
- Windows-核心编程-09-如何用内核对象进行线程同步-信号内核对象
- <<windows核心编程>>读书笔记---第9章 内核对象进行线程同步