Subj : Re: Challenge: Multithreading & Synchronization To : comp.programming.threads From : doug Date : Wed May 18 2005 11:20 pm "Uenal Mutlu" <520001085531-0001@t-online.de> wrote in message news:d6gd5u$20r$02$1@news.t-online.com... > BTW, as can been this solution also has a simple and effient method to > make any class with a standard constructor (incl. STL classes) thread > safe. > It's done like this: > > Lockable > myvec; > > To lock the object within a block of code and to unlock automatically > when it goes out of scope one uses the following: > Locker(myvec.m); > > or, one can lock and unlocks it also "manually" by: > myvec.m.lock(); > ... > myvec.m.unlock(); > > > > > "Uenal Mutlu" wrote >> /* >> Here's my solution. >> >> It applies the deadlock theorem, and by this it is deadlock-free, and >> everything is also thread-safe. >> >> The right order of the locks is obviously important (it follows the >> deadlock theorem). >> >> Performance is theoretically the fastest possible (unless someone >> uses hand crafted assembler code). >> >> It's that simple by using recursive mutex and applying the deadlock >> theorem. >> >> */ >> >> >> //---------------------------------------------------------- >> // recursive mutex: >> class rmutex >> { >> public: >> rmutex() { /*..*/ } >> ~rmutex() { /*..*/ } >> void lock() { /*..*/ } >> void unlock() { /*..*/ } >> }; >> >> //---------------------------------------------------------- >> // helper classes: >> >> class Locker >> { >> public: >> Locker(rmutex& Am) : m(Am) { m.lock(); } >> ~Locker() { m.unlock(); } >> private: >> rmutex& m; >> }; >> >> template class Lockable : public T >> { public: rmutex m; }; // uses recursive mutex >> >> >> //---------------------------------------------------------- >> // The "Server" class: >> >> #include >> >> >> struct SessionData >> { >> int iSessId; >> //... >> }; >> >> struct JobData >> { >> int iJobId; >> //... >> }; >> >> struct MiscData >> { >> int iMiscId; >> //... >> }; >> >> >> class Server >> { >> public: >> Server() >> { >> } >> >> ~Server() >> { >> } >> >> // assume all public functions can make calls to each other, >> // and also to internal funcs >> >> void f1(void* Ap = 0) >> { // uses vJD, vMD >> Locker L1(vJD.m); // the order of the locks is important >> Locker L2(vMD.m); >> >> //... >> } >> >> void f2(void* Ap = 0) >> { // uses vMD, vSD >> Locker L1(vSD.m); >> Locker L2(vMD.m); >> >> //... >> } >> >> void f3(void* Ap = 0) >> { // uses vSD, vMD >> Locker L1(vSD.m); >> Locker L2(vMD.m); >> >> //... >> } >> >> void f4(void* Ap = 0) >> { // uses vJD >> Locker L(vJD.m); >> >> //... >> } >> >> void f5(void* Ap = 0) >> { // uses vMD, vJD, vSD >> Locker L1(vSD.m); >> Locker L2(vJD.m); >> Locker L3(vMD.m); >> >> //... >> } >> >> void f6(void* Ap = 0) >> { // uses vMD >> Locker L(vMD.m); >> >> //... >> } >> >> void f7(void* Ap = 0) >> { // uses vMD >> Locker L(vMD.m); >> >> //... >> } >> >> void f8(void* Ap = 0) >> { // uses none >> >> //... >> } >> >> void f9(void* Ap = 0) >> { // uses vMD, vJD, vSD >> Locker L1(vSD.m); >> Locker L2(vJD.m); >> Locker L3(vMD.m); >> >> //... >> } >> >> >> private: >> >> // assume all internal functions can make calls to each other. >> >> void if1(void* Ap = 0) >> { // uses vSD, vJD >> Locker L1(vSD.m); >> Locker L2(vJD.m); >> >> //... >> } >> >> void if2(void* Ap = 0) >> { // uses vSD, vMD >> Locker L1(vSD.m); >> Locker L2(vMD.m); >> >> //... >> } >> >> void if3(void* Ap = 0) >> { // uses vJD, vMD, vSD >> Locker L1(vSD.m); >> Locker L2(vJD.m); >> Locker L3(vMD.m); >> >> //... >> } >> >> void if4(void* Ap = 0) >> { // uses vMD >> Locker L(vMD.m); >> >> //... >> } >> >> void if5(void* Ap = 0) >> { // uses vSD, vMD >> Locker L1(vSD.m); >> Locker L2(vMD.m); >> >> //... >> } >> >> >> private: >> // shared data: accessed by most member functions: >> // all data members are independent of each other >> Lockable > vSD; >> Lockable > vJD; >> Lockable > vMD; >> }; >> >> //---------------------------------------------------------- >> Server gServer; // only 1 Server object exists in application >> >> extern bool IsPgmTerminating(); >> >> void* thread_proc(void* Ap) // all threads use the same one thread proc >> { // no need to write code for this func >> // client gets registered and unregistered in gServer by the calling >> thread >> >> while (!IsPgmTerminating()) >> { >> // serve client by calling functions of gServer >> } >> >> return 0; >> } >> >> //---------------------------------------------------------- > > > You do know that an 'atomic counter' involves synchronisation, right? .