正在看网上下载的多线程的串口读写。看到CRITICAL_SECTION有些不解!看了看MSDN还是不太明白。以下是我的理解,请指正。当我的一个线程调用函数,在执行这个函数时遇到EnterCriticalSection( &g_csTest ),则他判断是否已经有别的线程已经进入。如果有的话等待(还是如何?)别的线程LeaveCriticalSection(&g_csTest)。不知是否如此?
比如我有一个多线程对一个文件读写:CRITICAL_SECTION g_csTest;
int nCounter;
CFile myfile;
......
InitializeCriticalSection(&m_csTest);
......void TestThread( LPVOID pParam )
{
char szMsg[128];
........
EnterCriticalSection( &g_csTest );
WriteTest( szMsg );
LeaveCriticalSection(&g_csTest);}
......
void WriteTest( char* pszMsg )
{
......
myfile.Opne(... );
myfile.Write(...);
myfile.Close( );
}这样能对一个文件多个线程安全读写吗?
比如我有一个多线程对一个文件读写:CRITICAL_SECTION g_csTest;
int nCounter;
CFile myfile;
......
InitializeCriticalSection(&m_csTest);
......void TestThread( LPVOID pParam )
{
char szMsg[128];
........
EnterCriticalSection( &g_csTest );
WriteTest( szMsg );
LeaveCriticalSection(&g_csTest);}
......
void WriteTest( char* pszMsg )
{
......
myfile.Opne(... );
myfile.Write(...);
myfile.Close( );
}这样能对一个文件多个线程安全读写吗?
EnterCriticalSection 表示进入临界区:
如果成功,可以对其下的数据有完全的控制权。
如果不成功,则线程被挂起直到别的线程退出临界区。 但它只限于在同一进程的不同线程中使用。
所谓临界区,就是程序中的一段代码,该代码涉及到对临界资源的访问。临界资源,就是一次只允许一个进程访问的资源。打个比方,比如火车上的厕所,男女共用,一次只允许一个人使用,这就是典型的临界资源,为了保证一次只有一个人用厕所,所以厕所上有一个牌子,上书“有人”或“无人”,这其实是信号量最典型的应用。当一个人要上厕所的时候,他会先看牌子上写的是“有人”,还是“无人”,如果有人,则等待里面的人释放临界资源(厕所);如果“无人”,则进入临界区(准备上厕所),并将牌子改成“有人”,以便提示下一个人,现在有人在使用临界资源(厕所),请稍候。操作系统这时一般都把等待的进程插入阻塞队列,以免产生忙等,释放CPU给其他进程,以提高CPU利用率。
实现进程同步的方法还有很多,如邮箱,管程等。这些属于高级通信方式,建议你去找一本关于OS的教材,上面都讲的很详细。
如果我在对共享变量(比如g_Flag)进行访问前,
忘了使用 EnterCriticalSection( &g_csTest),我还能对g_Flag的值进行修改吗?
请看关于进程同步的经典问题:生产者-消费者问题:
现在假设代码中的CFile是一个固定大小的缓冲区,有m个生产者进程和k个消费者进程,生产者往缓冲区内投放产品,消费者从缓冲区中取走产品。如果缓冲区中为空,那么将不允许消费者进入CS;如果缓冲区已满,那么将不允许生产者进入CS。
则Test-and-Lock方法将实效。首先,当一个读进程准备进入缓冲区时,它必须判断,1,当前是否有进程在访问临界资源,2.缓冲区是否为空。若两者均否,则进入临界区,否则等待。对写者与之类似。所以该问题需要二个用于同步的信号量:一个用来说明空缓冲单元数目,设为empty,初值为缓冲区大小n,一个用来说明缓冲单元的数目,设为full,初值为0,因为有界缓冲区是一个临界资源,必须互斥使用,还要设一个互斥信号量mutex,初值为1。
解决算法如下:
int full=0; //满缓冲单元数目
int empty=n; //空缓冲单元数目
int mutex=1; //对有界缓冲区进行互斥操作的信号量
main()
{
begin
producer_i(); //i=1,2,……m
consumer_j(); //j=1,2,……k
end
}
producer_i()
{
while(生产未完成)
{
生产一个产品;
p(empty); //防止向满的缓冲区中投放产品
p(mutex); //确保没有消费者在访问缓冲区
送一个产品到缓冲区;
v(mutex);
v(full);
}
}
consumer_i()
{
while(还要继续消费)
{
p(full);
p(mutex);
拿走一个产品;
v(mutex);
v(empty);
}
}
更简单的理解,可以把信号量看成信号灯,进程根据“灯亮灯灭”然后相机行事。
2。我对事件(EVENT)的理解对否?只不过他(进程)在等待这个全局变量的值改变的时候把CPU的控制权交给了主线程!
“
能不能更通俗的讲讲?比如以下是我的理解,不知对不对,请斧正!
其实,我感觉EVENT和一个全局变量的整型差不多。由多个线程根据他的值(EVENT的状态)来判断是否等待还是向下执行!比如,程序开始的时候让这个全局变量为0,然后一个线程要执行某个操作时先判断这个整数是否为1(我们这里假设1表示可以执行),如果不是,就等待(等别的线程完成操作,把他设置成1),直到为1。他的ResetEvent就相当于把这个整数值重新设置成0。不知理解对否?
”
应该是视编译器而定。如果pv操作没有成对出现,会造成其他进程永远无法访问临界资源的危险。
1)不懂你所说的“用两个临界量来限制”是什么意思。信号量本来就是用来保证对临界量进行互斥访问和协调进程同步的,临界量本身需要用信号量来保护,你所说的“用两个临界量来限制”,我不知道你能用临界量来限制什么?
如果你的意思是上面的生产者-消费者问题可以用2个信号量的话,你就错了。
请再看题目,我们可以归纳出两条限制:
(1)若缓冲区为空,不允许消费者进入缓冲区;若缓冲区已满,不允许生产者投放产品。
(2)缓冲区本身也是一个临界资源,必须互斥访问,这是必须注意的。
假如只用一个全局变量n来表示缓冲区的空余空间大小(当然也可以用来表示缓冲区已使用的大小),那么,
如果是生产者,它将判断:n>0?是,
有其他进程在缓冲区内吗?否。
进入缓冲区,n--
如果是消费者,与之类似。但是,这样一来,我们用来表示缓冲区剩余空间大小的变量又变成了 临界资源 ,因为如果同时有生产者和消费者准备访问缓冲区,又同时开始判断n,然后分别对n施加了++和--操作,那么就混乱了。
所以势必对n要设一个互斥信号量,控制对n的互斥访问。
这个问题与帖主的问题不同处在于,生产者和消费者之间存在着某种合作关系,一方需要另一方为前提,所以要用信号量严格限制这两种进程代码执行时顺序,因为我们知道,现代的OS都是支持多任务的,程序调入内存后,根本不知道其中涉及对临界资源访问的代码何时被执行,何种情况下被执行,当然也就无法通过简单方法来限定:我这段代码必须要在你那段代码之前执行。
为了解决这个问题,信号量是一种方法。
该对象的全局HANDLE和一个COUNT,初值为1。
当有一个线程访问
EnterCriticalSection( &g_csTest );段的数据时,count-1,
直到 LeaveCriticalSection(&g_csTest);
count才加1
其它线程必须等到count为正才能访问,否则等待操作系统调度访问,
一旦count为1就可以访问
WriteTest( szMsg );并把count-1
看来是遇到行家了!那么麻烦您老人家看看我对的临界量的理解对不对!我的帖子的开头是我的理解!
理解正确. codewarrior(会思考的草)例子举非常好了.
哈哈,我想你也应该比我小。不过“您老人家”是我的习惯&敬称!期待你的再次解答!
你给出的程序只有个大概轮廓,我猜想那个全局变量nCount是用来记录有几个读进程的。第一个读进程将负责提醒写进程:此时不要进入CS。但读进程之间是不互斥的,允许多个读进程同时进入CS,对文件进行读写。但最后一个离开CS的读进程必须提醒写进程:人都走光了,你可以进来了。单从目前所给的程序来看,你的理解是正确的。