⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readme.cv

📁 windows多线程开发包
💻 CV
📖 第 1 页 / 共 5 页
字号:
README.CV -- Condition Variables
--------------------------------

The original implementation of condition variables in
pthreads-win32 was based on a discussion paper:

"Strategies for Implementing POSIX Condition Variables
on Win32": http://www.cs.wustl.edu/~schmidt/win32-cv-1.html

The changes suggested below were made on Feb 6 2001. This
file is included in the package for the benefit of anyone
interested in understanding the pthreads-win32 implementation
of condition variables and the (sometimes subtle) issues that
it attempts to resolve.

Thanks go to the individuals whose names appear throughout
the following text.

Ross Johnson

--------------------------------------------------------------------

fyi.. (more detailed problem description/demos + possible fix/patch)

regards,
alexander.


Alexander Terekhov
31.01.2001 17:43

To:   ace-bugs@cs.wustl.edu
cc:
From: Alexander Terekhov/Germany/IBM@IBMDE
Subject:  Implementation of POSIX CVs: spur.wakeups/lost
      signals/deadlocks/unfairness



    ACE VERSION:

        5.1.12 (pthread-win32 snapshot 2000-12-29)

    HOST MACHINE and OPERATING SYSTEM:

        IBM IntelliStation Z Pro, 2 x XEON 1GHz, Win2K

    TARGET MACHINE and OPERATING SYSTEM, if different from HOST:
    COMPILER NAME AND VERSION (AND PATCHLEVEL):

        Microsoft Visual C++ 6.0

    AREA/CLASS/EXAMPLE AFFECTED:

        Implementation of POSIX condition variables - OS.cpp/.h

    DOES THE PROBLEM AFFECT:

        EXECUTION? YES!

    SYNOPSIS:

        a) spurious wakeups (minor problem)
        b) lost signals
        c) broadcast deadlock
        d) unfairness (minor problem)

    DESCRIPTION:

        Please see attached copy of discussion thread
        from comp.programming.threads for more details on
        some reported problems. (i've also posted a "fyi"
        message to ace-users a week or two ago but
        unfortunately did not get any response so far).

        It seems that current implementation suffers from
        two essential problems:

        1) cond.waiters_count does not accurately reflect
           number of waiters blocked on semaphore - w/o
           proper synchronisation that could result (in the
           time window when counter is not accurate)
           in spurious wakeups organised by subsequent
           _signals  and _broadcasts.

        2) Always having (with no e.g. copy_and_clear/..)
           the same queue in use (semaphore+counter)
           neither signal nor broadcast provide 'atomic'
           behaviour with respect to other threads/subsequent
           calls to signal/broadcast/wait.

        Each problem and combination of both could produce
        various nasty things:

        a) spurious wakeups (minor problem)

             it is possible that waiter(s) which was already
             unblocked even so is still counted as blocked
             waiter. signal and broadcast will release
             semaphore which will produce a spurious wakeup
             for a 'real' waiter coming later.

        b) lost signals

             signalling thread ends up consuming its own
             signal. please see demo/discussion below.

        c) broadcast deadlock

             last_waiter processing code does not correctly
             handle the case with multiple threads
             waiting for the end of broadcast.
             please see demo/discussion below.

        d) unfairness (minor problem)

             without SignalObjectAndWait some waiter(s)
             may end up consuming broadcasted signals
             multiple times (spurious wakeups) because waiter
             thread(s) can be preempted before they call
             semaphore wait (but after count++ and mtx.unlock).

    REPEAT BY:

        See below... run problem demos programs (tennis.cpp and
        tennisb.cpp) number of times concurrently (on multiprocessor)
        and in multiple sessions or just add a couple of "Sleep"s
        as described in the attached copy of discussion thread
        from comp.programming.threads

    SAMPLE FIX/WORKAROUND:

        See attached patch to pthread-win32.. well, I can not
        claim that it is completely bug free but at least my
        test and tests provided by pthreads-win32 seem to work.
        Perhaps that will help.

        regards,
        alexander.


>> Forum: comp.programming.threads
>> Thread: pthread_cond_* implementation questions
.
.
.
David Schwartz <davids@webmaster.com> wrote:

> terekhov@my-deja.com wrote:
>
>> BTW, could you please also share your view on other perceived
>> "problems" such as nested broadcast deadlock, spurious wakeups
>> and (the latest one) lost signals??
>
>I'm not sure what you mean. The standard allows an implementation
>to do almost whatever it likes. In fact, you could implement
>pthread_cond_wait by releasing the mutex, sleeping a random
>amount of time, and then reacquiring the mutex. Of course,
>this would be a pretty poor implementation, but any code that
>didn't work under that implementation wouldn't be strictly
>compliant.

The implementation you suggested is indeed correct
one (yes, now I see it :). However it requires from
signal/broadcast nothing more than to "{ return 0; }"
That is not the case for pthread-win32 and ACE
implementations. I do think that these implementations
(basically the same implementation) have some serious
problems with wait/signal/broadcast calls. I am looking
for help to clarify whether these problems are real
or not. I think that I can demonstrate what I mean
using one or two small sample programs.
.
.
.
==========
tennis.cpp
==========

#include "ace/Synch.h"
#include "ace/Thread.h"

enum GAME_STATE {

  START_GAME,
  PLAYER_A,     // Player A playes the ball
  PLAYER_B,     // Player B playes the ball
  GAME_OVER,
  ONE_PLAYER_GONE,
  BOTH_PLAYERS_GONE

};

enum GAME_STATE             eGameState;
ACE_Mutex*                  pmtxGameStateLock;
ACE_Condition< ACE_Mutex >* pcndGameStateChange;

void*
  playerA(
    void* pParm
  )
{

  // For access to game state variable
  pmtxGameStateLock->acquire();

  // Play loop
  while ( eGameState < GAME_OVER ) {

    // Play the ball
    cout << endl << "PLAYER-A" << endl;

    // Now its PLAYER-B's turn
    eGameState = PLAYER_B;

    // Signal to PLAYER-B that now it is his turn
    pcndGameStateChange->signal();

    // Wait until PLAYER-B finishes playing the ball
    do {

      pcndGameStateChange->wait();

      if ( PLAYER_B == eGameState )
        cout << endl << "----PLAYER-A: SPURIOUS WAKEUP!!!" << endl;

    } while ( PLAYER_B == eGameState );

  }

  // PLAYER-A gone
  eGameState = (GAME_STATE)(eGameState+1);
  cout << endl << "PLAYER-A GONE" << endl;

  // No more access to state variable needed
  pmtxGameStateLock->release();

  // Signal PLAYER-A gone event
  pcndGameStateChange->broadcast();

  return 0;

}

void*
  playerB(
    void* pParm
  )
{

  // For access to game state variable
  pmtxGameStateLock->acquire();

  // Play loop
  while ( eGameState < GAME_OVER ) {

    // Play the ball
    cout << endl << "PLAYER-B" << endl;

    // Now its PLAYER-A's turn
    eGameState = PLAYER_A;

    // Signal to PLAYER-A that now it is his turn
    pcndGameStateChange->signal();

    // Wait until PLAYER-A finishes playing the ball
    do {

      pcndGameStateChange->wait();

      if ( PLAYER_A == eGameState )
        cout << endl << "----PLAYER-B: SPURIOUS WAKEUP!!!" << endl;

    } while ( PLAYER_A == eGameState );

  }

  // PLAYER-B gone
  eGameState = (GAME_STATE)(eGameState+1);
  cout << endl << "PLAYER-B GONE" << endl;

  // No more access to state variable needed
  pmtxGameStateLock->release();

  // Signal PLAYER-B gone event
  pcndGameStateChange->broadcast();

  return 0;

}


int
main (int, ACE_TCHAR *[])
{

  pmtxGameStateLock   = new ACE_Mutex();
  pcndGameStateChange = new ACE_Condition< ACE_Mutex >( *pmtxGameStateLock
);

  // Set initial state
  eGameState = START_GAME;

  // Create players
  ACE_Thread::spawn( playerA );
  ACE_Thread::spawn( playerB );

  // Give them 5 sec. to play
  Sleep( 5000 );//sleep( 5 );

  // Set game over state
  pmtxGameStateLock->acquire();
  eGameState = GAME_OVER;

  // Let them know
  pcndGameStateChange->broadcast();

  // Wait for players to stop
  do {

    pcndGameStateChange->wait();

  } while ( eGameState < BOTH_PLAYERS_GONE );

  // Cleanup
  cout << endl << "GAME OVER" << endl;
  pmtxGameStateLock->release();
  delete pcndGameStateChange;
  delete pmtxGameStateLock;

  return 0;

}

===========
tennisb.cpp
===========
#include "ace/Synch.h"
#include "ace/Thread.h"

enum GAME_STATE {

  START_GAME,
  PLAYER_A,     // Player A playes the ball
  PLAYER_B,     // Player B playes the ball
  GAME_OVER,
  ONE_PLAYER_GONE,
  BOTH_PLAYERS_GONE

};

enum GAME_STATE             eGameState;
ACE_Mutex*                  pmtxGameStateLock;
ACE_Condition< ACE_Mutex >* pcndGameStateChange;

void*
  playerA(
    void* pParm
  )
{

  // For access to game state variable
  pmtxGameStateLock->acquire();

  // Play loop
  while ( eGameState < GAME_OVER ) {

    // Play the ball
    cout << endl << "PLAYER-A" << endl;

    // Now its PLAYER-B's turn
    eGameState = PLAYER_B;

    // Signal to PLAYER-B that now it is his turn
    pcndGameStateChange->broadcast();

    // Wait until PLAYER-B finishes playing the ball
    do {

      pcndGameStateChange->wait();

      if ( PLAYER_B == eGameState )
        cout << endl << "----PLAYER-A: SPURIOUS WAKEUP!!!" << endl;

    } while ( PLAYER_B == eGameState );

  }

  // PLAYER-A gone
  eGameState = (GAME_STATE)(eGameState+1);
  cout << endl << "PLAYER-A GONE" << endl;

  // No more access to state variable needed
  pmtxGameStateLock->release();

  // Signal PLAYER-A gone event
  pcndGameStateChange->broadcast();

  return 0;

}

void*
  playerB(
    void* pParm
  )
{

  // For access to game state variable
  pmtxGameStateLock->acquire();

  // Play loop
  while ( eGameState < GAME_OVER ) {

    // Play the ball
    cout << endl << "PLAYER-B" << endl;

    // Now its PLAYER-A's turn
    eGameState = PLAYER_A;

    // Signal to PLAYER-A that now it is his turn
    pcndGameStateChange->broadcast();

    // Wait until PLAYER-A finishes playing the ball
    do {

      pcndGameStateChange->wait();

      if ( PLAYER_A == eGameState )
        cout << endl << "----PLAYER-B: SPURIOUS WAKEUP!!!" << endl;

    } while ( PLAYER_A == eGameState );

  }

  // PLAYER-B gone
  eGameState = (GAME_STATE)(eGameState+1);
  cout << endl << "PLAYER-B GONE" << endl;

  // No more access to state variable needed
  pmtxGameStateLock->release();

  // Signal PLAYER-B gone event
  pcndGameStateChange->broadcast();

  return 0;

}


int
main (int, ACE_TCHAR *[])
{

  pmtxGameStateLock   = new ACE_Mutex();
  pcndGameStateChange = new ACE_Condition< ACE_Mutex >( *pmtxGameStateLock
);

  // Set initial state
  eGameState = START_GAME;

  // Create players
  ACE_Thread::spawn( playerA );
  ACE_Thread::spawn( playerB );

  // Give them 5 sec. to play
  Sleep( 5000 );//sleep( 5 );

  // Make some noise
  pmtxGameStateLock->acquire();
  cout << endl << "---Noise ON..." << endl;
  pmtxGameStateLock->release();
  for ( int i = 0; i < 100000; i++ )
    pcndGameStateChange->broadcast();
  cout << endl << "---Noise OFF" << endl;

  // Set game over state
  pmtxGameStateLock->acquire();
  eGameState = GAME_OVER;
  cout << endl << "---Stopping the game..." << endl;

  // Let them know
  pcndGameStateChange->broadcast();

  // Wait for players to stop
  do {

    pcndGameStateChange->wait();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -