Win32Mutex.cpp
上传用户:chinafayin
上传日期:2022-04-05
资源大小:153k
文件大小:5k
源码类别:

并行计算

开发平台:

Visual C++

  1. //
  2. // OpenThread library, Copyright (C) 2002 - 2003  The Open Thread Group
  3. //
  4. // This library is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU Lesser General Public
  6. // License as published by the Free Software Foundation; either
  7. // version 2.1 of the License, or (at your option) any later version.
  8. //
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. // Lesser General Public License for more details.
  13. // 
  14. // You should have received a copy of the GNU Lesser General Public
  15. // License along with this library; if not, write to the Free Software
  16. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17. //
  18. //
  19. // Win32Mutex.c++ - C++ Mutex class .
  20. // The idea for it is borrowed from SGI STL
  21. // It looks like it's hard to use win32 CRITICALL_SECTIONS withour introducing race 
  22. // conditions on InitializeCriticalSection() . So we use spin mutex here.
  23. // ~~~~~~~~~~~~~~~~
  24. //
  25. #include "../Mutex"
  26. #include "Win32MutexPrivateData.h"
  27. using namespace OpenThreads;
  28. Win32MutexPrivateData::~Win32MutexPrivateData()
  29. {
  30. }
  31. template <int instance>
  32. struct WIN32MutexSpin {
  33.   enum { __low_max = 30, __high_max = 1000 };
  34.   // Low if we suspect uniprocessor, high for multiprocessor.
  35.   static unsigned __max;
  36.   static unsigned __last;
  37. };
  38. template <int instance>
  39. unsigned WIN32MutexSpin <instance>::__max = WIN32MutexSpin <instance>::__low_max;
  40. template <int instance>
  41. unsigned WIN32MutexSpin <instance>::__last = 0;
  42. static void _S_nsec_sleep(int __log_nsec) {
  43.     if (__log_nsec <= 20) {
  44.         Sleep(0);
  45.      } else {
  46.         Sleep(1 << (__log_nsec - 20));
  47.      }
  48. }
  49. #if defined(_MSC_VER) && _MSC_VER <= 1300
  50. template WIN32MutexSpin <0>;
  51. #endif
  52. //----------------------------------------------------------------------------
  53. //
  54. // Decription: Constructor
  55. //
  56. // Use: public.
  57. //
  58. Mutex::Mutex() {
  59.     Win32MutexPrivateData *pd = new Win32MutexPrivateData();
  60.     pd->mutex  = 0;
  61.     _prvData = static_cast<void *>(pd);
  62. }
  63. //----------------------------------------------------------------------------
  64. //
  65. // Decription: Destructor
  66. //
  67. // Use: public.
  68. //
  69. Mutex::~Mutex() {
  70.     unlock();
  71.     delete static_cast<Win32MutexPrivateData*>(_prvData);
  72. }
  73. //----------------------------------------------------------------------------
  74. //
  75. // Decription: lock the mutex
  76. //
  77. // Use: public.
  78. //
  79. int Mutex::lock() {
  80.     Win32MutexPrivateData *pd =
  81.         static_cast<Win32MutexPrivateData*>(_prvData);
  82.     volatile unsigned long* lock = &pd->mutex;
  83. // InterlockedExchange returns old value
  84. // if old_value  == 0 mutex wasn't locked , now it is
  85. if( !InterlockedExchange((long*)lock, 1L)) {
  86.        return 0;
  87.     }
  88.     unsigned my_spin_max = WIN32MutexSpin<0>::__max;
  89.     unsigned my_last_spins = WIN32MutexSpin<0>::__last;
  90.     volatile unsigned junk = 17;      
  91.     unsigned i;
  92.     for (i = 0; i < my_spin_max; i++) {
  93.       if (i < my_last_spins/2 || *lock) {
  94.         junk *= junk; junk *= junk;
  95.         junk *= junk; junk *= junk;
  96.         continue;
  97.       }
  98.       if (!InterlockedExchange((long*)lock, 1L)) {
  99.         // got it!
  100.         // Spinning worked.  Thus we're probably not being scheduled
  101.         // against the other process with which we were contending.
  102.         // Thus it makes sense to spin longer the next time.
  103.         WIN32MutexSpin<0>::__last = i;
  104.         WIN32MutexSpin<0>::__max = WIN32MutexSpin<0>::__high_max;
  105.         return 0;
  106.       }
  107.     }
  108.     // We are probably being scheduled against the other process.  Sleep.
  109.     WIN32MutexSpin<0>::__max = WIN32MutexSpin<0>::__low_max;
  110.     for (i = 0 ;; ++i) {
  111.       int __log_nsec = i + 6;
  112.       if (__log_nsec > 27) __log_nsec = 27;
  113.       if (!InterlockedExchange((long*)lock, 1L)) {
  114.         return 0;
  115.       }
  116.       _S_nsec_sleep(__log_nsec);
  117.     }
  118. }
  119. //----------------------------------------------------------------------------
  120. //
  121. // Decription: unlock the mutex
  122. //
  123. // Use: public.
  124. //
  125. int Mutex::unlock() {
  126.     Win32MutexPrivateData *pd =
  127.         static_cast<Win32MutexPrivateData*>(_prvData);
  128.     volatile unsigned long* lock = &pd->mutex;
  129.     *lock = 0;
  130.     // This is not sufficient on many multiprocessors, since
  131.     // writes to protected variables and the lock may be reordered.
  132. return 0;
  133. }
  134. //----------------------------------------------------------------------------
  135. //
  136. // Decription: test if the mutex may be locked
  137. //
  138. // Use: public.
  139. //
  140. int Mutex::trylock() {
  141.     Win32MutexPrivateData *pd =
  142.         static_cast<Win32MutexPrivateData*>(_prvData);
  143.     volatile unsigned long* lock = &pd->mutex;
  144. if( !InterlockedExchange((long*)lock, 1L)) {
  145.       return 1; // TRUE
  146.     }
  147. return 0; // FALSE
  148. }