PATCH: for "Strange testsuite/thread/pthread1.cc"

Loren James Rittle rittle@latour.rsch.comm.mot.com
Fri Jan 25 19:35:00 GMT 2002


[...]
> I don't see how it can work. You have no control which thread will run
> at any given time. As the result, produce/consume may send singal to 
> itself, which leads to dead lock. It happens on Linux/mips. May I ask
> why only one condition variable is used?

Hi H.J.,

Thanks for the report.  This code was written long before I knew it
was going in as a portable test case.  Even so, I think the code is
logically correct against the standard.  However, I could agree that
it does something quirky (i.e. not in common use).  Since it is
debatable whether the issue is in the test case or the thread
implementation (I don't wish to have the debate since I don't have a
copy of 1003.1c-1995 handy at the moment) and since the purpose of the
test case is not to stress test a POSIX thread implementation, I will
change the test to use one condition variable per signaling direction.

Regarding why only one condition variable is required in this special
case IMHO: There are exactly two threads sharing any particular
condition variable.  May a thread ever send a condition signal to
itself?  By definition, absolutely not.  In practice, I think this is
the issue with the deadlocking thread implementation (I vaguely recall
this issue having been discussed many moons ago).

If a thread is in the pthread_cond_signal() call, by definition, the
same thread may not be in the pthread_cond_wait() call.  By
definition, condition signals are never held.  Thus, at most, only the
other thread using the same condition variable may be in
pthread_cond_wait() at the moment a condition is signaled.  If it is
in that call, it must get the condition signal.  If it is not, it is
lost forever.

If you see a thread ever consume its own condition signal, then IMHO
your POSIX thread implementation has a subtle bug that should be fixed.

Applied after manually testing the change on i386-unknown-freebsd4.4.

Regards,
Loren

        * testsuite/thread/pthread1.cc: Use one condition variable
        per predicate instead of tricky use of one condition variable.

Index: libstdc++-v3/testsuite/thread/pthread1.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/thread/pthread1.cc,v
retrieving revision 1.2
diff -c -r1.2 pthread1.cc
*** pthread1.cc	2002/01/25 16:05:48	1.2
--- pthread1.cc	2002/01/26 03:20:57
***************
*** 48,66 ****
    task_queue ()
    {
      pthread_mutex_init (&fooLock, NULL);
!     pthread_cond_init (&fooCond, NULL);
    }
    ~task_queue ()
    {
      pthread_mutex_destroy (&fooLock);
!     pthread_cond_destroy (&fooCond);
    }
    list<int> foo;
    pthread_mutex_t fooLock;
!   // This code uses a special case that allows us to use just one
!   // condition variable - in general, don't use this idiom unless you
!   // know what you are doing. ;-)
!   pthread_cond_t fooCond;
  };
  
  void*
--- 48,66 ----
    task_queue ()
    {
      pthread_mutex_init (&fooLock, NULL);
!     pthread_cond_init (&fooCond1, NULL);
!     pthread_cond_init (&fooCond2, NULL);
    }
    ~task_queue ()
    {
      pthread_mutex_destroy (&fooLock);
!     pthread_cond_destroy (&fooCond1);
!     pthread_cond_destroy (&fooCond2);
    }
    list<int> foo;
    pthread_mutex_t fooLock;
!   pthread_cond_t fooCond1;
!   pthread_cond_t fooCond2;
  };
  
  void*
***************
*** 72,80 ****
      {
        pthread_mutex_lock (&tq.fooLock);
        while (tq.foo.size () >= max_size)
! 	pthread_cond_wait (&tq.fooCond, &tq.fooLock);
        tq.foo.push_back (num++);
!       pthread_cond_signal (&tq.fooCond);
        pthread_mutex_unlock (&tq.fooLock);
      }
    return 0;
--- 72,80 ----
      {
        pthread_mutex_lock (&tq.fooLock);
        while (tq.foo.size () >= max_size)
! 	pthread_cond_wait (&tq.fooCond1, &tq.fooLock);
        tq.foo.push_back (num++);
!       pthread_cond_signal (&tq.fooCond2);
        pthread_mutex_unlock (&tq.fooLock);
      }
    return 0;
***************
*** 89,99 ****
      {
        pthread_mutex_lock (&tq.fooLock);
        while (tq.foo.size () == 0)
! 	pthread_cond_wait (&tq.fooCond, &tq.fooLock);
        if (tq.foo.front () != num++)
  	abort ();
        tq.foo.pop_front ();
!       pthread_cond_signal (&tq.fooCond);
        pthread_mutex_unlock (&tq.fooLock);
      }
    return 0;
--- 89,99 ----
      {
        pthread_mutex_lock (&tq.fooLock);
        while (tq.foo.size () == 0)
! 	pthread_cond_wait (&tq.fooCond2, &tq.fooLock);
        if (tq.foo.front () != num++)
  	abort ();
        tq.foo.pop_front ();
!       pthread_cond_signal (&tq.fooCond1);
        pthread_mutex_unlock (&tq.fooLock);
      }
    return 0;



More information about the Libstdc++ mailing list