[C++/Win32] My thread class is not working

Started by
14 comments, last by the_edd 14 years, 3 months ago
Just a few quick notes:

Quote:Original post by the_edd
0. Don't do this yourself, unless it's just for fun. There's already a defacto-standard C++ threading interface.

Boost threads is one of these libraries in Boost that somehow leaves you scratching your head. The designers of that library made some really strange design decisions, that make some real world MT systems very awkward and inefficient to implement. The heavily Unix-biased choice of synchronisation primitives is also very problematic under Windows (eg. conditions variables, which are non-native on XP, and the lack of events, which are native and commonly encountered throughout Windows). The technical details of all this are a different topic altogether, but suffice to say that writing your own threading library is actually rather common, mainly due to Boost:thread's weirdness. It is, however, rather non-trivial and requires a very good understanding of MT concepts.

Quote:Original post by the_edd
3. Priority and suspend/resume functionality are almost always useless.

Actually, lowering thread priority is very useful. I would even go as far as saying that priority support is vital for a threading library.
Advertisement
Quote:Original post by Yann L
Boost threads is one of these libraries in Boost that somehow leaves you scratching your head. The designers of that library made some really strange design decisions, that make some real world MT systems very awkward and inefficient to implement. The heavily Unix-biased choice of synchronisation primitives is also very problematic under Windows (eg. conditions variables, which are non-native on XP, and the lack of events, which are native and commonly encountered throughout Windows).

Efficient implementations of the primitives in boost threads are possible on Windows (though the Windows API might not be used) else C++ wouldn't be standardising on it. Of course, possible != available, necessarily.

Quote:The technical details of all this are a different topic altogether, but suffice to say that writing your own threading library is actually rather common, mainly due to Boost:thread's weirdness. It is, however, rather non-trivial and requires a very good understanding of MT concepts.


I tend to find the the Windows threading functionality far stranger e.g. the naming of CRITICAL_SECTION, the way you have to bend over backwards to use WaitForMultipleObjects with more than MAXIMUM_WAIT_OBJECTS handles, the special meanings for Sleep() with special values as arguments. To each their own though, I guess.

Quote:Actually, lowering thread priority is very useful. I would even go as far as saying that priority support is vital for a threading library.

I can't say I've ever found the need to do that. I tend to design things so that either a thread is doing some work that I want done ASAP or waiting (idling) for that work to arrive.
Battousai: if I'm getting your class to thread mapping concept right, then m_bRunning is not correctly reset if the thread ends itself.

Quote:Original post by the_edd
Efficient implementations of the primitives in boost threads are possible on Windows (though the Windows API might not be used) else C++ wouldn't be standardising on it.

Implementation details, especially platform specific ones, were not even considered by the C++ standarization committee.

Quote:Original post by the_edd
Of course, possible != available, necessarily.

It is impossible to efficiently implement condition variables on pre-Vista, since they are unsupported by the kernel. A good CV implementation on XP (ie. one that will never deadlock and is well balanced in all situations), relying on semaphores and mutexes, is surprisingly complex and dead inefficient. Have a look at how Boost::threads implements it.

While native kernel CVs exist in Vista and above, their use will lead to code that behaves radically differently on XP, performance wise.

Quote:Original post by the_edd
I tend to find the the Windows threading functionality far stranger e.g. the naming of CRITICAL_SECTION, the way you have to bend over backwards to use WaitForMultipleObjects with more than MAXIMUM_WAIT_OBJECTS handles, the special meanings for Sleep() with special values as arguments. To each their own though, I guess.

I agree that Windows threading is a bit bizarre. But Windows representing 90%+ of the PC market, it should be the primary driving platform for standarization. Especially for a concept which is so OS dependent as threading.

Quote:Original post by the_edd
I can't say I've ever found the need to do that. I tend to design things so that either a thread is doing some work that I want done ASAP or waiting (idling) for that work to arrive.

There are many scenarios where lowering the priority can be useful. It gives valuable hints to the scheduler on how to assign time slices amongst a set of candidate threads. An example would be a realtime 3D application that requires entirely smooth motion, with a background network thread that will periodically use a lot of CPU. Lowering the latter threads' priority can help to avoid sudden glitches or lags in the animation thread. It is also very important for single CPU systems, or multi-CPU scenarios with fixed core affinities.

Anyway, this is probably a bit offtopic :)
Quote:Original post by Yann L
Quote:Original post by the_edd
Efficient implementations of the primitives in boost threads are possible on Windows (though the Windows API might not be used) else C++ wouldn't be standardising on it.

Implementation details, especially platform specific ones, were not even considered by the C++ standarization committee.

Surely they have to be? If the unofficial motto for C++ is that "you don't pay for what you don't need" and the threading functionality isn't widely implementable at minimal cost, then it wouldn't (and probably shouldn't IMVHO) be standardized.

Quote:
It is impossible to efficiently implement condition variables on pre-Vista, since they are unsupported by the kernel. A good CV implementation on XP (ie. one that will never deadlock and is well balanced in all situations), relying on semaphores and mutexes, is surprisingly complex and dead inefficient. Have a look at how Boost::threads implements it.

Is that even true given that an implementation can be written in assembler? I'm genuinely interested. I don't know enough about the kernel/user-space boundaries here.

Quote:
I agree that Windows threading is a bit bizarre. But Windows representing 90%+ of the PC market, it should be the primary driving platform for standarization. Especially for a concept which is so OS dependent as threading.

Windows is 90% of the desktop market. It is run on nowhere near 90% of the machines that can be targeted by C++.

EDIT: to clarify, I was taking issue with the "primary driving platform" part. I agree that implementation details for a platform as widespread as Windows should be considered.

Quote:
Quote:Original post by the_edd
I can't say I've ever found the need to do that. I tend to design things so that either a thread is doing some work that I want done ASAP or waiting (idling) for that work to arrive.

There are many scenarios where lowering the priority can be useful. It gives valuable hints to the scheduler on how to assign time slices amongst a set of candidate threads.

These hints are also OS-specific though, no? I mean XP vs Vista, not just Windows vs non-Windows.

Quote:An example would be a realtime 3D application that requires entirely smooth motion, with a background network thread that will periodically use a lot of CPU.


If you mean realtime in the stricter sense, then I can see how that would be useful. But on your common or garden desktop OS, I would use select()/WaitForMultipleObjects() for such a thing. The handling code is short and sharp and creates a response that is thrown at a thread pool or task queue.

Quote:
Lowering the latter threads' priority can help to avoid sudden glitches or lags in the animation thread.

I think this is where the crux of my "designs" differ; I tend not to give any thread one particular responsibility. I think anything that helps you think in terms of tasks rather than threads can only be a good thing.

Quote:Anyway, this is probably a bit offtopic :)

Indeed, this will be my last. You now have a free rein on rebuttals :)

[Edited by - the_edd on December 27, 2009 9:41:20 PM]
Quote:Original post by Yann L
Battousai: if I'm getting your class to thread mapping concept right, then m_bRunning is not correctly reset if the thread ends itself.

That's one to-do, you are right. I have to write a few lines for it.

Quote:Original post by Yann L
Anyway, this is probably a bit offtopic :)

I enjoy good debates even if they are off topic. It is good to know all of these.


I want to improve my class to obtain maximum performance on multi-core CPU systems. Do you have any idea how?
Quote:Original post by Battousai
I want to improve my class to obtain maximum performance on multi-core CPU systems. Do you have any idea how?


Your class won't be a bottleneck. The act of creating a thread should occur rarely.

I tend to create a pool of threads once (of size equal to boost::thread::hardware_concurrency()) and have everything go through that.

Designing performance in to threaded code from the outset is hard. The two basic things you can do are 1. make sure that you hold any locks you have for the shortest time possible and 2. avoid false sharing.

These articles are a good place to start reading about the remaining intricacies.

This topic is closed to new replies.

Advertisement