Subj : Re: Challenge: Multithreading & Synchronization To : comp.programming.threads From : doug Date : Thu May 19 2005 07:23 pm "Uenal Mutlu" <520001085531-0001@t-online.de> wrote in message news:d6i42p$gog$02$1@news.t-online.com... > "Maciej Sobczak" wrote >> Uenal Mutlu wrote: >> >> What should be thread-safe, in fact, is the overall state of your >> program, not the >> state of each separate brick. The scope of this overall state is usually >> much broader than a single value object. Don't think in terms of >> "independent objects". If they were independent, you wouldn't put them >> all in the same program. > > Ok, a much better term would be "independently accessible objects". > If one is locked then any other thread wanting to use one of the > non-locked objects can still continue its job; so it is not forced to > wait. > > Of course your program will work even with just only 1 global mutex for > everything too, > but by using a finer locking granularity you could get better performance. > It of course depends on the data. > > We've usually the following cases: > > // case0: exclusive access to all objects; the whole app has just 1 mutex: > void f() > { > Locker L(app.m); > for (size_t i = 0; i < vec.size(); i++) > { > // manipulate vec > } > } > > // case1: exclusive access to an object: > void f() > { > Locker L(vec.m); > for (size_t i = 0; i < vec.size(); i++) > { > // manipulate vec > } > } > > // case2: shared access to an object: > void f() > { > for (size_t i = 0; i < vec.size(); i++) > { > Locker L(vec.m); > // manipulate vec > } > } > > With many threads and high concurrency case2 mostly would > lead to the fastest performance, although it might look counter-intuitive. > This case would be a good choice for a realtime application. > But mostly case1 is sufficient. > Case0 usually would lead to the slowest performance. > > If there are independently accessible objects then in a > hi-speed time criticial (highly concurrent) app one better > should try case1 first and then try to extend it to use case2. > For usual GUI apps case1 is mostly the better choice. > Case0 should be used only when porting a single threading > app to multithreading in the first stage, in later stages it should > be extended to use case1. > > That's my philosophy. > > Case 2 is broken. You check the size of the vector without a lock. For example - thread A calls the function, and rolls around int eh loop a few times... - thread A checks size of vector in while loop, and sees it is about to manipulate the last element. It does this without a lock - thread B locks the vector and removes the last item in it - thread A locks the vector tries to access the (now removed) last item - SEGSEGV here we come If you've tested this, you've not tested it properly. Damn, I said I wasn't going to post again. In the spirit of anticipation, and because I think I know what you're like now, I believe you'll try and cry off this bug with the following excuses: "but there is no way to remove an item, so that bug can't happen" - I'd say, well, there's still a bug - someone could add an item, and another thread in f() might miss it - or worse, if the item is inserted in the middle of the vector, might process an item twice - You might then say, "there's no function to add to the vector either". I'd then say, "bit of a stupid program, then, isn't it? Can't really get much done." I'd also say "if you can't add or remove from the vector, just use an array." But you'll likely have some sad story for that too. Like how linked-list traversal is faster than array access, cats and dogs living in peace, etc. "it was just an example" - then it proves a point the rest of us are trying to get across. Your post is all full of assertions. It should be full of questions, because you don't yet understand multi-threaded programming. Doug .