Advertisement
Guest User

Untitled

a guest
Mar 1st, 2024
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.23 KB | None | 0 0
  1. #include <assert.h>
  2. #include <atomic>
  3. #include <cstdint>
  4. #include <iostream>
  5. #include <memory>
  6. #include <shared_mutex>
  7. #include <thread>
  8. #include <vector>
  9.  
  10. #if 0
  11. constexpr const int kNumThreads = 5;
  12.  
  13. struct ThreadTestData {
  14.     std::shared_mutex sharedMutex = {};
  15.     std::atomic<int32_t> readCounter;
  16. };
  17.  
  18. int DoStuff(ThreadTestData* data) {
  19.     // Acquire reader lock
  20.     data->sharedMutex.lock_shared();
  21.  
  22.     // wait until all read threads have acquired their shared lock
  23.     data->readCounter.fetch_add(1);
  24.     while (data->readCounter.load() != kNumThreads) {
  25.         std::this_thread::yield();
  26.     }
  27.  
  28.     // Release reader lock
  29.     data->sharedMutex.unlock_shared();
  30.  
  31.     return 0;
  32. }
  33.  
  34. int main() {
  35.     int count = 0;
  36.     while (true) {
  37.         ThreadTestData data = {};
  38.  
  39.         // Acquire write lock
  40.         data.sharedMutex.lock();
  41.  
  42.         // Create N threads
  43.         std::vector<std::unique_ptr<std::thread>> readerThreads;
  44.         readerThreads.reserve(kNumThreads);
  45.         for (int i = 0; i < kNumThreads; ++i) {
  46.             readerThreads.emplace_back(std::make_unique<std::thread>(DoStuff, &data));
  47.         }
  48.  
  49.         // Release write lock
  50.         data.sharedMutex.unlock();
  51.  
  52.         // Wait for all readers to succeed
  53.         for (auto& thread : readerThreads) {
  54.             thread->join();
  55.         }
  56.  
  57.         // Cleanup
  58.         readerThreads.clear();
  59.  
  60.         // Spew so we can tell when it's deadlocked
  61.         count += 1;
  62.         std::cout << count << std::endl;
  63.     }
  64.  
  65.     return 0;
  66. }
  67. #else
  68. #include <Windows.h>
  69. #include <winternl.h>
  70.  
  71. using NtYieldExecutionFunc = uint32_t(*)(void);
  72. NtYieldExecutionFunc ntYieldExecution = nullptr;
  73.  
  74. struct ThreadTestData
  75. {
  76.     HANDLE hEvent;
  77.     SRWLOCK SRWLock = {};
  78.     LONG numThreads = 1;
  79.     LONG readCounter = 0;
  80.  
  81.     void EndThread()
  82.     {
  83.         if (!InterlockedDecrementNoFence(&numThreads))
  84.         {
  85.             if (!SetEvent(hEvent)) __debugbreak();
  86.         }
  87.     }
  88.  
  89.     void DoStuff()
  90.     {
  91.         AcquireSRWLockShared(&SRWLock);
  92.  
  93.         ULONG n = 0, m = 0, k = InterlockedDecrementNoFence(&readCounter);
  94.  
  95.         while (readCounter)
  96.         {
  97.             switch (ntYieldExecution())
  98.             {
  99.             case /*STATUS_SUCCESS*/0:
  100.                 n++;
  101.                 break;
  102.             case /*STATUS_NO_YIELD_PERFORMED*/0x40000024L:
  103.                 m++;
  104.                 break;
  105.             default:
  106.                 __debugbreak();
  107.             }
  108.         }
  109.  
  110.         ReleaseSRWLockShared(&SRWLock);
  111.  
  112.         //std::cout << k << ">" << n << "/" << m << std::endl;
  113.  
  114.         EndThread();
  115.     }
  116.  
  117.     static ULONG WINAPI _S_DoStuff(PVOID data)
  118.     {
  119.         reinterpret_cast<ThreadTestData*>(data)->DoStuff();
  120.         return 0;
  121.     }
  122.  
  123.     void Test(ULONG n)
  124.     {
  125.         if (hEvent = CreateEventW(0, 0, 0, 0))
  126.         {
  127.             AcquireSRWLockExclusive(&SRWLock);
  128.  
  129.             do
  130.             {
  131.                 numThreads++;
  132.                 readCounter++;
  133.  
  134.                 if (HANDLE hThread = CreateThread(0, 0, _S_DoStuff, this, 0, 0))
  135.                 {
  136.                     CloseHandle(hThread);
  137.                 }
  138.                 else
  139.                 {
  140.                     readCounter--;
  141.                     numThreads--;
  142.                 }
  143.  
  144.             } while (--n);
  145.  
  146.             ReleaseSRWLockExclusive(&SRWLock);
  147.  
  148.             EndThread();
  149.  
  150.             if (WAIT_OBJECT_0 != WaitForSingleObject(hEvent, INFINITE))
  151.             {
  152.                 __debugbreak();
  153.             }
  154.  
  155.             CloseHandle(hEvent);
  156.         }
  157.     }
  158. };
  159.  
  160. int main()
  161. {
  162.     auto ntdll = LoadLibraryA("ntdll.dll");
  163.     assert(ntdll);
  164.     ntYieldExecution = (NtYieldExecutionFunc)GetProcAddress(ntdll, "NtYieldExecution");
  165.  
  166.     int count = 0;
  167.     while (true) {
  168.         ThreadTestData data;
  169.         data.Test(8);
  170.  
  171.         count += 1;
  172.         std::cout << "Count: " << count << std::endl;
  173.     }
  174.  
  175.     return 0;
  176. }
  177.  
  178. #endif
  179.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement