void RwLock::EnterRead() { LLOG("EnterRead"); write_mutex.Enter(); lock_mutex.Enter(); readers++; lock_mutex.Leave(); write_mutex.Leave(); LLOG(".EnterRead"); }
bool Thread::Run(Callback _cb) { LLOG("Thread::Run"); AtomicInc(sThreadCount); if(!threadr) #ifndef CPU_BLACKFIN threadr = sMain = true; #else { threadr = true; //the sMain replacement #ifdef PLATFORM_POSIX pthread_t thid = pthread_self(); vm.Enter(); if(threadsv.Find(thid) < 0){ //thread not yet present, mark present threadsv.Add(thid); } else RLOG("BUG: Multiple Add in Mt.cpp"); vm.Leave(); #endif } #endif Detach(); Callback *cb = new Callback(_cb); #ifdef PLATFORM_WIN32 handle = (HANDLE)_beginthreadex(0, 0, sThreadRoutine, cb, 0, ((unsigned int *)(&thread_id))); #endif #ifdef PLATFORM_POSIX if(pthread_create(&handle, 0, sThreadRoutine, cb)) handle = 0; #endif return handle; }
void RwLock::LeaveWrite() { LLOG("LeaveWrite"); lock_mutex.Enter(); lock_mutex.Leave(); write_mutex.Leave(); LLOG(".LeaveWrite"); }
void RwLock::EnterWrite() { LLOG("EnterWrite"); write_mutex.Enter(); LLOG("EnterWrite:write_mutex.Enter();"); lock_mutex.Enter(); ASSERT(!waiting_writer); waiting_writer = true; if(readers) { LLOG("EnterWrite:if(readers)"); lock_mutex.Leave(); writer_wait.Wait(); lock_mutex.Enter(); LLOG("EnterWrite:writer_wait.Wait();"); } waiting_writer = false; lock_mutex.Leave(); LLOG(".EnterWrite"); }
void ProducerThread() { for(int i = 0; i < N; i++) { if(i % 1000 == 0) LOG(i); mutex.Enter(); queue.AddHead() = new int; mutex.Leave(); todo.Release(); MemoryCheckDebug(); } LOG("Producer shutdown"); }
void MutexTutorial() { /// .`Mutex` /// Mutex ("mutual exclusion") is a well known concept in multithreaded programming: When /// multiple threads write and read the same data, the access has to be serialized using /// Mutex. Following invalid code demonstrates why: Thread t; int sum = 0; t.Run([&sum] { for(int i = 0; i < 1000000; i++) sum++; }); for(int i = 0; i < 1000000; i++) sum++; t.Wait(); DUMP(sum); /// While the expected value is 2000000, produced value is different. The problem is that /// both thread read / modify / write `sum` value without any locking. Using `Mutex` locks /// the `sum` and thus serializes access to it - read / modify / write sequence is now /// exclusive for the thread that has `Mutex` locked, this fixing the issue. `Mutex` can be /// locked / unlocked with `Enter` / `Leave` methods. Alternatively, `Mutex::Lock` helper /// class locks `Mutex` in constructor and unlocks it in destructor: Mutex m; sum = 0; t.Run([&sum, &m] { for(int i = 0; i < 1000000; i++) { m.Enter(); sum++; m.Leave(); } }); for(int i = 0; i < 1000000; i++) { Mutex::Lock __(m); // Lock m till the end of scope sum++; } t.Wait(); DUMP(sum); /// }
Thread::~Thread() { Detach(); #ifdef CPU_BLACKFIN #ifdef PLATFORM_POSIX //the static destruction replacement pthread_t thid = pthread_self(); vm.Enter(); int id = threadsv.Find(thid); if(id >= 0) threadsv.Remove(id); vm.Leave(); #endif #endif }
void RwLock::LeaveRead() { LLOG("LeaveRead"); lock_mutex.Enter(); LLOG("LeaveRead:lock_mutex.Enter();"); if(--readers == 0 && waiting_writer) { LLOG("LeaveRead:if(--readers == 0 && writer)"); ASSERT(readers == 0); writer_wait.Release(); LLOG("LeaveRead:writer_wait.Release();"); } LLOG("LeaveRead:--readers"); lock_mutex.Leave(); LLOG(".LeaveRead"); }
void RefObjects::BuryDeadites() { if (_dead_list.Empty()) return; // Copy dead list DListForward dead_list; m_refobjects_lock.Enter(); dead_list.Steal(_dead_list); m_refobjects_lock.Leave(); for (iter ii = dead_list; ii; ++ii) { if (ii->OnFinalize()) delete ii; } }
bool Thread::IsMain() //the calling thread is the Main Thread or the only one in App { #ifndef CPU_BLACKFIN return !threadr || sMain; #else if(!threadr) return true; #ifdef PLATFORM_POSIX //the sMain replacement pthread_t thid = pthread_self(); vm.Enter(); if(threadsv.Find(thid) >= 0) { vm.Leave(); return true; } vm.Leave(); #endif return false; #endif }
AutoMutex::AutoMutex(Mutex &mutex) { _mutex = &mutex; mutex.Enter(); }
bool RefObjects::Entrypoint(void *param) { CAT_INANE("RefObjects") << "Reaper starting..."; while (!_shutdown_flag.Wait(513)) { BuryDeadites(); } CAT_INANE("RefObjects") << "Reaper caught shutdown signal, setting asynchronous shutdown flag..."; m_refobjects_lock.Enter(); _shutdown = true; // Now the shutdown flag is set everywhere synchronously. // The lists may only be modified from this function. m_refobjects_lock.Leave(); CAT_INANE("RefObjects") << "Reaper destroying remaining active objects..."; // For each remaining active object, for (iter ii = _active_list; ii; ++ii) { ii->Destroy(CAT_REFOBJECT_TRACE); } CAT_INANE("RefObjects") << "Reaper burying any easy dead..."; BuryDeadites(); CAT_INANE("RefObjects") << "Reaper spinning and finalizing the remaining active objects..."; static const u32 HANG_THRESHOLD = 3000; // ms static const u32 SLEEP_TIME = 10; // ms u32 hang_counter = 0; // While active objects still exist, CAT_FOREVER { // Troll for zero reference counts for (iter ii = _active_list; ii; ++ii) { // If reference count hits zero, if (ii->_ref_count != 0) continue; #if defined(CAT_TRACE_REFOBJECT) CAT_INANE("RefObjects") << ii->GetRefObjectName() << "#" << ii.GetRef() << " finalizing"; #endif _active_list.Erase(ii); // If object finalizing requests memory freed, if (ii->OnFinalize()) { #if defined(CAT_TRACE_REFOBJECT) CAT_INANE("RefObjects") << ii->GetRefObjectName() << "#" << ii.GetRef() << " freeing memory"; #endif delete ii; } // Reset hang counter hang_counter = 0; } // Quit when active list is empty if (_active_list.Empty()) break; // Find smallest ref count object iter smallest_obj = _active_list; u32 smallest_ref_count = smallest_obj->_ref_count; iter ii = _active_list; while (++ii) { if (ii->_ref_count < smallest_ref_count) { smallest_ref_count = ii->_ref_count; smallest_obj = ii; } } CAT_INANE("RefObjects") << smallest_obj->GetRefObjectName() << "#" << smallest_obj.GetRef() << " finalization delayed with " << smallest_ref_count << " dangling references (smallest found)"; // If active list is not empty and hang count hasn't exceeded threshold, if (++hang_counter < HANG_THRESHOLD) { Clock::sleep(SLEEP_TIME); continue; } CAT_FATAL("RefObjects") << smallest_obj->GetRefObjectName() << "#" << smallest_obj.GetRef() << " finalization FORCED with " << smallest_ref_count << " dangling references (smallest found)"; _active_list.Erase(smallest_obj); // If object finalizing requests memory freed, if (smallest_obj->OnFinalize()) { CAT_FATAL("RefObjects") << smallest_obj->GetRefObjectName() << "#" << smallest_obj.GetRef() << " freeing memory for forced finalize"; delete smallest_obj; } // Reset hang counter hang_counter = 0; } CAT_INANE("RefObjects") << "...Reaper going to sleep in a quiet field of dead objects"; return true; }