正在看网上下载的多线程的串口读写。看到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( );
}这样能对一个文件多个线程安全读写吗?

解决方案 »

  1.   

    CRITICAL_SECTION 就是所谓的临界区对象,使用时它被定义为一个全局变量。它首先需要被初始化:InitializeCriticalSection(&m_csTest);
    EnterCriticalSection 表示进入临界区: 
     如果成功,可以对其下的数据有完全的控制权。
     如果不成功,则线程被挂起直到别的线程退出临界区。 但它只限于在同一进程的不同线程中使用。
      

  2.   

    &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&现在讨论讨论EVENT吧!请大家解释以下EVENT这个东东!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&请大家解释以下EVENT这个东东!什么 SetEvent(m_hEvent1), ResetEvent(m_hEvent1),等等这些EVENT的操作!MSDN我都看了,不过不是很明白!请大家用通俗的语言解释一下!谢谢!
      

  3.   

    其实Event和信号量的作用差不多,都是用来保持对临界资源的互斥访问的。
    所谓临界区,就是程序中的一段代码,该代码涉及到对临界资源的访问。临界资源,就是一次只允许一个进程访问的资源。打个比方,比如火车上的厕所,男女共用,一次只允许一个人使用,这就是典型的临界资源,为了保证一次只有一个人用厕所,所以厕所上有一个牌子,上书“有人”或“无人”,这其实是信号量最典型的应用。当一个人要上厕所的时候,他会先看牌子上写的是“有人”,还是“无人”,如果有人,则等待里面的人释放临界资源(厕所);如果“无人”,则进入临界区(准备上厕所),并将牌子改成“有人”,以便提示下一个人,现在有人在使用临界资源(厕所),请稍候。操作系统这时一般都把等待的进程插入阻塞队列,以免产生忙等,释放CPU给其他进程,以提高CPU利用率。
    实现进程同步的方法还有很多,如邮箱,管程等。这些属于高级通信方式,建议你去找一本关于OS的教材,上面都讲的很详细。
      

  4.   

    能不能更通俗的讲讲?比如以下是我的理解,不知对不对,请斧正!其实,我感觉EVENT和一个全局变量的整型差不多。由多个线程根据他的值(EVENT的状态)来判断是否等待还是向下执行!比如,程序开始的时候让这个全局变量为0,然后一个线程要执行某个操作时先判断这个整数是否为1(我们这里假设1表示可以执行),如果不是,就等待(等别的线程完成操作,把他设置成1),直到为1。他的ResetEvent就相当于把这个整数值重新设置成0。不知理解对否?
      

  5.   

    强烈建议你去买一本《win32多线程编程》,侯捷译
      

  6.   

    我想问一下:不管是临界区、互斥量、信号量或是事件,是否对所有的共享数据进行访问控制?这里的共享数据是否就是全局变量?
        
       如果我在对共享变量(比如g_Flag)进行访问前,
    忘了使用 EnterCriticalSection( &g_csTest),我还能对g_Flag的值进行修改吗?
      

  7.   

    帖主所理解的EVENT是解决同步问题的一种解法,叫测试并上锁。这种解法只能解决很简单的进程同步问题。MSDN中关于Event的函数我不太清楚。这种处理方法,适用于:一次只允许一个进程进入CS(临界区,下同),而不管这个进程是读进程还是写进程。但是如果给这个问题加入其他的限制,Test-and-Lock方法就无法解决了。
    请看关于进程同步的经典问题:生产者-消费者问题:
    现在假设代码中的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);
        }
    }
      

  8.   

    另外,用于互斥的信号量的P,V操作,一般出现在同一个代码段中,而用于通信的信号量的P,V操作,一般出现在两个不同的代码段中。
    更简单的理解,可以把信号量看成信号灯,进程根据“灯亮灯灭”然后相机行事。
      

  9.   

    楼上的:我想问的是,如果我在放或者是拿时,忘了使用p( ) and v( ),编译或是执行时编译器会发现这一潜在的问题吗??
      

  10.   

    to: codewarrior(会思考的草),谢谢你的指点!还有以下几点疑问,请解答!1。“还要设一个互斥信号量mutex”?为什么?我用两个临界量来限制不行吗?
    2。我对事件(EVENT)的理解对否?只不过他(进程)在等待这个全局变量的值改变的时候把CPU的控制权交给了主线程!

    能不能更通俗的讲讲?比如以下是我的理解,不知对不对,请斧正!
    其实,我感觉EVENT和一个全局变量的整型差不多。由多个线程根据他的值(EVENT的状态)来判断是否等待还是向下执行!比如,程序开始的时候让这个全局变量为0,然后一个线程要执行某个操作时先判断这个整数是否为1(我们这里假设1表示可以执行),如果不是,就等待(等别的线程完成操作,把他设置成1),直到为1。他的ResetEvent就相当于把这个整数值重新设置成0。不知理解对否?
      

  11.   

    to:sz_chendong(ChenDong) 
    应该是视编译器而定。如果pv操作没有成对出现,会造成其他进程永远无法访问临界资源的危险。
      

  12.   

    to:jfzsl(剿匪总司令)
    1)不懂你所说的“用两个临界量来限制”是什么意思。信号量本来就是用来保证对临界量进行互斥访问和协调进程同步的,临界量本身需要用信号量来保护,你所说的“用两个临界量来限制”,我不知道你能用临界量来限制什么?
    如果你的意思是上面的生产者-消费者问题可以用2个信号量的话,你就错了。
    请再看题目,我们可以归纳出两条限制:
    (1)若缓冲区为空,不允许消费者进入缓冲区;若缓冲区已满,不允许生产者投放产品。
    (2)缓冲区本身也是一个临界资源,必须互斥访问,这是必须注意的。
    假如只用一个全局变量n来表示缓冲区的空余空间大小(当然也可以用来表示缓冲区已使用的大小),那么,
    如果是生产者,它将判断:n>0?是,
                            有其他进程在缓冲区内吗?否。
                             进入缓冲区,n--
    如果是消费者,与之类似。但是,这样一来,我们用来表示缓冲区剩余空间大小的变量又变成了 临界资源 ,因为如果同时有生产者和消费者准备访问缓冲区,又同时开始判断n,然后分别对n施加了++和--操作,那么就混乱了。
    所以势必对n要设一个互斥信号量,控制对n的互斥访问。
    这个问题与帖主的问题不同处在于,生产者和消费者之间存在着某种合作关系,一方需要另一方为前提,所以要用信号量严格限制这两种进程代码执行时顺序,因为我们知道,现代的OS都是支持多任务的,程序调入内存后,根本不知道其中涉及对临界资源访问的代码何时被执行,何种情况下被执行,当然也就无法通过简单方法来限定:我这段代码必须要在你那段代码之前执行。
    为了解决这个问题,信号量是一种方法。
      

  13.   

    2)帖主理解的EVENT,和我上面举的例子中的那个n是一样的。都是用来表示临界资源所剩的大小。它本身也是临界资源(因为进程进入CS之后将对其进行修改)。
      

  14.   

    产生一个CRITICAL_SECTION时候,系统在Kernel32.dll的帮助下产生一个属于
    该对象的全局HANDLE和一个COUNT,初值为1。
    当有一个线程访问
    EnterCriticalSection( &g_csTest );段的数据时,count-1,
    直到    LeaveCriticalSection(&g_csTest);
    count才加1
    其它线程必须等到count为正才能访问,否则等待操作系统调度访问,
    一旦count为1就可以访问
        WriteTest( szMsg );并把count-1
      

  15.   

    sorry,下午DSP要考试,晚上再来和大家一起讨论!
      

  16.   

    to: jfzsl(剿匪总司令) 
    看来是遇到行家了!那么麻烦您老人家看看我对的临界量的理解对不对!我的帖子的开头是我的理解!
    理解正确. codewarrior(会思考的草)例子举非常好了.
      

  17.   

    to: codewarrior(会思考的草) 
    哈哈,我想你也应该比我小。不过“您老人家”是我的习惯&敬称!期待你的再次解答!
      

  18.   

    to: jfzsl(剿匪总司令)
    你给出的程序只有个大概轮廓,我猜想那个全局变量nCount是用来记录有几个读进程的。第一个读进程将负责提醒写进程:此时不要进入CS。但读进程之间是不互斥的,允许多个读进程同时进入CS,对文件进行读写。但最后一个离开CS的读进程必须提醒写进程:人都走光了,你可以进来了。单从目前所给的程序来看,你的理解是正确的。