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

📄 readme.cv

📁 windows多线程开发包
💻 CV
📖 第 1 页 / 共 5 页
字号:
#ifdef NEED_SEM

      result = (ptw32_increase_semaphore( &cv->sema, cv->waiters )
                 ? 0
                : EINVAL);

#else /* NEED_SEM */

      result = (ReleaseSemaphore( cv->sema, cv->waiters, NULL )
                 ? 0
                : EINVAL);

#endif /* NEED_SEM */

    }

  (void) pthread_mutex_unlock(&(cv->waitersLock));

  if (wereWaiters && result == 0)
    {(wereWaiters
      /*
       * Wait for all the awakened threads to acquire their part of
       * the counting semaphore
       */

      if (WaitForSingleObject (cv->waitersDone, INFINITE)
          == WAIT_OBJECT_0)
        {
          result = 0;
        }
      else
        {
          result = EINVAL;
        }

    }

  return (result);

}

BTW, on my system (2 CPUs) I can manage to get
the program stalled even without any source code
modification if I run the tennisb program many
times in different shell sessions.

===================
pthread-win32 patch
===================
struct pthread_cond_t_ {
  long            nWaitersBlocked;   /* Number of threads blocked
*/
  long            nWaitersUnblocked; /* Number of threads unblocked
*/
  long            nWaitersToUnblock; /* Number of threads to unblock
*/
  sem_t           semBlockQueue;     /* Queue up threads waiting for the
*/
                                     /*   condition to become signalled
*/
  sem_t           semBlockLock;      /* Semaphore that guards access to
*/
                                     /* | waiters blocked count/block queue
*/
                                     /* +-> Mandatory Sync.LEVEL-1
*/
  pthread_mutex_t mtxUnblockLock;    /* Mutex that guards access to
*/
                                     /* | waiters (to)unblock(ed) counts
*/
                                     /* +-> Optional* Sync.LEVEL-2
*/
};                                   /* Opt*) for _timedwait and
cancellation*/

int
pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr)
  int result = EAGAIN;
  pthread_cond_t cv = NULL;

  if (cond == NULL)
    {(cond
      return EINVAL;
    }

  if ((attr != NULL && *attr != NULL) &&
      ((*attr)->pshared == PTHREAD_PROCESS_SHARED))
    {
      /*
       * Creating condition variable that can be shared between
       * processes.
       */
      result = ENOSYS;

      goto FAIL0;
    }

  cv = (pthread_cond_t) calloc (1, sizeof (*cv));

  if (cv == NULL)
    {(cv
      result = ENOMEM;
      goto FAIL0;
    }

  cv->nWaitersBlocked   = 0;
  cv->nWaitersUnblocked = 0;
  cv->nWaitersToUnblock = 0;

  if (sem_init (&(cv->semBlockLock), 0, 1) != 0)
    {(sem_init
      goto FAIL0;
    }

  if (sem_init (&(cv->semBlockQueue), 0, 0) != 0)
    {(sem_init
      goto FAIL1;
    }

  if (pthread_mutex_init (&(cv->mtxUnblockLock), 0) != 0)
    {(pthread_mutex_init
      goto FAIL2;
    }


  result = 0;

  goto DONE;

  /*
   * -------------
   * Failed...
   * -------------
   */
FAIL2:
  (void) sem_destroy (&(cv->semBlockQueue));

FAIL1:
  (void) sem_destroy (&(cv->semBlockLock));

FAIL0:
DONE:
  *cond = cv;

  return (result);

}                               /* pthread_cond_init */

int
pthread_cond_destroy (pthread_cond_t * cond)
{
  int result = 0;
  pthread_cond_t cv;

  /*
   * Assuming any race condition here is harmless.
   */
  if (cond == NULL
      || *cond == NULL)
    {
      return EINVAL;
    }

  if (*cond != (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
    {(*cond
      cv = *cond;

      /*
       * Synchronize access to waiters blocked count (LEVEL-1)
       */
      if (sem_wait(&(cv->semBlockLock)) != 0)
        {(sem_wait(&(cv->semBlockLock))
          return errno;
        }

      /*
       * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
       */
      if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
        {((result
          (void) sem_post(&(cv->semBlockLock));
          return result;
        }

      /*
       * Check whether cv is still busy (still has waiters blocked)
       */
      if (cv->nWaitersBlocked - cv->nWaitersUnblocked > 0)
        {(cv->nWaitersBlocked
          (void) sem_post(&(cv->semBlockLock));
          (void) pthread_mutex_unlock(&(cv->mtxUnblockLock));
          return EBUSY;
        }

      /*
       * Now it is safe to destroy
       */
      (void) sem_destroy (&(cv->semBlockLock));
      (void) sem_destroy (&(cv->semBlockQueue));
      (void) pthread_mutex_unlock (&(cv->mtxUnblockLock));
      (void) pthread_mutex_destroy (&(cv->mtxUnblockLock));

      free(cv);
      *cond = NULL;
    }
  else
    {
      /*
       * See notes in ptw32_cond_check_need_init() above also.
       */
      EnterCriticalSection(&ptw32_cond_test_init_lock);

      /*
       * Check again.
       */
      if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
        {(*cond
          /*
           * This is all we need to do to destroy a statically
           * initialised cond that has not yet been used (initialised).
           * If we get to here, another thread
           * waiting to initialise this cond will get an EINVAL.
           */
          *cond = NULL;
        }
      else
        {
          /*
           * The cv has been initialised while we were waiting
           * so assume it's in use.
           */
          result = EBUSY;
        }

      LeaveCriticalSection(&ptw32_cond_test_init_lock);
    }

  return (result);
}

/*
 * Arguments for cond_wait_cleanup, since we can only pass a
 * single void * to it.
 */
typedef struct {
  pthread_mutex_t * mutexPtr;
  pthread_cond_t cv;
  int * resultPtr;
} ptw32_cond_wait_cleanup_args_t;

static void
ptw32_cond_wait_cleanup(void * args)
{
  ptw32_cond_wait_cleanup_args_t * cleanup_args =
(ptw32_cond_wait_cleanup_args_t *) args;
  pthread_cond_t cv = cleanup_args->cv;
  int * resultPtr = cleanup_args->resultPtr;
  int eLastSignal; /* enum: 1=yes 0=no -1=cancelled/timedout w/o signal(s)
*/
  int result;

  /*
   * Whether we got here as a result of signal/broadcast or because of
   * timeout on wait or thread cancellation we indicate that we are no
   * longer waiting. The waiter is responsible for adjusting waiters
   * (to)unblock(ed) counts (protected by unblock lock).
   * Unblock lock/Sync.LEVEL-2 supports _timedwait and cancellation.
   */
  if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
    {((result
      *resultPtr = result;
      return;
    }

  cv->nWaitersUnblocked++;

  eLastSignal = (cv->nWaitersToUnblock == 0) ?
                   -1 : (--cv->nWaitersToUnblock == 0);

  /*
   * No more LEVEL-2 access to waiters (to)unblock(ed) counts needed
   */
  if ((result = pthread_mutex_unlock(&(cv->mtxUnblockLock))) != 0)
    {((result
      *resultPtr = result;
      return;
    }

  /*
   * If last signal...
   */
  if (eLastSignal == 1)
    {(eLastSignal
     /*
      * ...it means that we have end of 'atomic' signal/broadcast
      */
      if (sem_post(&(cv->semBlockLock)) != 0)
        {(sem_post(&(cv->semBlockLock))
          *resultPtr = errno;
          return;
        }
    }
  /*
   * If not last signal and not timed out/cancelled wait w/o signal...
   */
  else if (eLastSignal == 0)
    {
     /*
      * ...it means that next waiter can go through semaphore
      */
      if (sem_post(&(cv->semBlockQueue)) != 0)
        {(sem_post(&(cv->semBlockQueue))
          *resultPtr = errno;
          return;
        }
    }

  /*
   * XSH: Upon successful return, the mutex has been locked and is owned
   * by the calling thread
   */
  if ((result = pthread_mutex_lock(cleanup_args->mutexPtr)) != 0)
    {((result
      *resultPtr = result;
    }

}                               /* ptw32_cond_wait_cleanup */

static int
ptw32_cond_timedwait (pthread_cond_t * cond,
                      pthread_mutex_t * mutex,
                      const struct timespec *abstime)
{
  int result = 0;
  pthread_cond_t cv;
  ptw32_cond_wait_cleanup_args_t cleanup_args;

  if (cond == NULL || *cond == NULL)
    {(cond
      return EINVAL;
    }

  /*
   * We do a quick check to see if we need to do more work
   * to initialise a static condition variable. We check
   * again inside the guarded section of ptw32_cond_check_need_init()
   * to avoid race conditions.
   */
  if (*cond == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
    {(*cond
      result = ptw32_cond_check_need_init(cond);
    }

  if (result != 0 && result != EBUSY)
    {(result
      return result;
    }

  cv = *cond;

  /*
   * Synchronize access to waiters blocked count (LEVEL-1)
   */
  if (sem_wait(&(cv->semBlockLock)) != 0)
    {(sem_wait(&(cv->semBlockLock))
      return errno;
    }

  cv->nWaitersBlocked++;

  /*
   * Thats it. Counted means waiting, no more access needed
   */
  if (sem_post(&(cv->semBlockLock)) != 0)
    {(sem_post(&(cv->semBlockLock))
      return errno;
    }

  /*
   * Setup this waiter cleanup handler
   */
  cleanup_args.mutexPtr = mutex;
  cleanup_args.cv = cv;
  cleanup_args.resultPtr = &result;

  pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args);

  /*
   * Now we can release 'mutex' and...
   */
  if ((result = pthread_mutex_unlock (mutex)) == 0)
    {((result

      /*
       * ...wait to be awakened by
       *              pthread_cond_signal, or
       *              pthread_cond_broadcast, or
       *              timeout, or
       *              thread cancellation
       *
       * Note:
       *
       *      ptw32_sem_timedwait is a cancellation point,
       *      hence providing the mechanism for making
       *      pthread_cond_wait a cancellation point.
       *      We use the cleanup mechanism to ensure we
       *      re-lock the mutex and adjust (to)unblock(ed) waiters
       *      counts if we are cancelled, timed out or signalled.
       */
      if (ptw32_sem_timedwait (&(cv->semBlockQueue), abstime) != 0)
        {(ptw32_sem_timedwait
          result = errno;
        }
    }

  /*
   * Always cleanup
   */
  pthread_cleanup_pop (1);


  /*
   * "result" can be modified by the cleanup handler.
   */
  return (result);

}                               /* ptw32_cond_timedwait */


static int
ptw32_cond_unblock (pthread_cond_t * cond,
                    int unblockAll)
{
  int result;
  pthread_cond_t cv;

  if (cond == NULL || *cond == NULL)
    {(cond
      return EINVAL;
    }

  cv = *cond;

  /*
   * No-op if the CV is static and hasn't been initialised yet.
   * Assuming that any race condition is harmless.
   */
  if (cv == (pthread_cond_t) PTW32_OBJECT_AUTO_INIT)
    {(cv
      return 0;
    }

  /*
   * Synchronize access to waiters blocked count (LEVEL-1)
   */
  if (sem_wait(&(cv->semBlockLock)) != 0)
    {(sem_wait(&(cv->semBlockLock))
      return errno;
    }

  /*
   * Synchronize access to waiters (to)unblock(ed) counts (LEVEL-2)
   * This sync.level supports _timedwait and cancellation
   */
  if ((result = pthread_mutex_lock(&(cv->mtxUnblockLock))) != 0)
    {((result
      return result;
    }

  /*
   * Adjust waiters blocked and unblocked counts (collect garbage)
   */
  if (cv->nWaitersUnblocked != 0)
    {(cv->nWaitersUnblocked
      cv->nWaitersBlocked  -= cv->nWaitersUnblocked;
      cv->nWaitersUnblocked = 0;
    }

  /*
   * If (after adjustment) there are still some waiters blocked counted...
   */
  if ( cv->nWaitersBlocked > 0)
    {(
      /*
       * We will unblock first waiter and leave semBlockLock/LEVEL-1 locked
       * LEVEL-1 access is left disabled until last signal/unblock
completes
       */

⌨️ 快捷键说明

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