1 // Hide VTK_DEPRECATED_IN_9_1_0() warnings for this class. 2 #define VTK_DEPRECATION_LEVEL 0 3 4 #include "vtkConditionVariable.h" 5 #include "vtkMultiThreader.h" 6 #include "vtksys/SystemTools.hxx" 7 8 #include <atomic> 9 #include <cstdlib> 10 11 struct vtkThreadUserData_t 12 { 13 vtkMutexLock* Lock; 14 vtkConditionVariable* Condition; 15 std::atomic<int32_t> Done; 16 int NumberOfWorkers; 17 }; 18 using vtkThreadUserData = struct vtkThreadUserData_t; 19 vtkTestCondVarThread(void * arg)20VTK_THREAD_RETURN_TYPE vtkTestCondVarThread(void* arg) 21 { 22 int threadId = static_cast<vtkMultiThreader::ThreadInfo*>(arg)->ThreadID; 23 int threadCount = static_cast<vtkMultiThreader::ThreadInfo*>(arg)->NumberOfThreads; 24 vtkThreadUserData* td = 25 static_cast<vtkThreadUserData*>(static_cast<vtkMultiThreader::ThreadInfo*>(arg)->UserData); 26 if (td) 27 { 28 if (threadId == 0) 29 { 30 td->Lock->Lock(); 31 td->Done = 0; 32 cout << "Thread " << (threadId + 1) << " of " << threadCount << " initializing.\n"; 33 cout.flush(); 34 td->Lock->Unlock(); 35 36 int i; 37 for (i = 0; i < 2 * threadCount; ++i) 38 { 39 td->Lock->Lock(); 40 cout << "Signaling (count " << i << ")...\n"; 41 cout.flush(); 42 td->Lock->Unlock(); 43 td->Condition->Signal(); 44 45 // sleep( 1 ); 46 } 47 48 i = 0; 49 int currNumWorkers = 0; 50 do 51 { 52 td->Lock->Lock(); 53 td->Done = 1; 54 cout << "Broadcasting...\n"; 55 cout.flush(); 56 currNumWorkers = td->NumberOfWorkers; 57 td->Lock->Unlock(); 58 td->Condition->Broadcast(); 59 vtksys::SystemTools::Delay(200); // 0.2 s between broadcasts 60 } while (currNumWorkers > 0 && (i++ < 1000)); 61 if (i >= 1000) 62 { 63 exit(2); 64 } 65 } 66 else 67 { 68 // Wait for thread 0 to initialize... Ugly but effective 69 bool done = false; 70 do 71 { 72 td->Lock->Lock(); 73 if (td->Done) 74 { 75 done = true; 76 td->Lock->Unlock(); 77 } 78 else 79 { 80 td->Lock->Unlock(); 81 vtksys::SystemTools::Delay(200); // 0.2 s between checking 82 } 83 } while (!done); 84 85 // Wait for the condition and then note we were signaled. 86 // This part looks like a Hansen Monitor: 87 // ref: http://www.cs.utexas.edu/users/lorenzo/corsi/cs372h/07S/notes/Lecture12.pdf (page 88 // 2/5), code on Tradeoff slide. 89 90 td->Lock->Lock(); 91 while (td->Done <= 0) 92 { 93 cout << " Thread " << (threadId + 1) << " waiting.\n"; 94 cout.flush(); 95 // Wait() performs an Unlock internally. 96 td->Condition->Wait(td->Lock); 97 // Once Wait() returns, the lock is locked again. 98 cout << " Thread " << (threadId + 1) << " responded.\n"; 99 cout.flush(); 100 } 101 --td->NumberOfWorkers; 102 td->Lock->Unlock(); 103 } 104 105 td->Lock->Lock(); 106 cout << " Thread " << (threadId + 1) << " of " << threadCount << " exiting.\n"; 107 cout.flush(); 108 td->Lock->Unlock(); 109 } 110 else 111 { 112 cout << "No thread data!\n"; 113 cout << " Thread " << (threadId + 1) << " of " << threadCount << " exiting.\n"; 114 cout.flush(); 115 } 116 117 return VTK_THREAD_RETURN_VALUE; 118 } 119 TestConditionVariable(int,char * [])120int TestConditionVariable(int, char*[]) 121 { 122 vtkMultiThreader* threader = vtkMultiThreader::New(); 123 int numThreads = threader->GetNumberOfThreads(); 124 125 vtkThreadUserData data; 126 data.Lock = vtkMutexLock::New(); 127 data.Condition = vtkConditionVariable::New(); 128 data.Done = -1; 129 data.NumberOfWorkers = numThreads - 1; 130 131 threader->SetNumberOfThreads(numThreads); 132 threader->SetSingleMethod(vtkTestCondVarThread, &data); 133 threader->SingleMethodExecute(); 134 135 cout << "Done with threader.\n"; 136 cout.flush(); 137 138 vtkIndent indent; 139 indent = indent.GetNextIndent(); 140 data.Condition->PrintSelf(cout, indent); 141 142 data.Lock->Delete(); 143 data.Condition->Delete(); 144 threader->Delete(); 145 return 0; 146 } 147