C++ standards for thread management

M

Morpheus

Hi,

I have been coding in Windows for many years so have a mindset to it,
so forgive any stupid questions.

Is it possible to create a multithread application in C++ that is
portable (OS/compiler)? In my Windows applications, I use
synchronization objects like, mutex, semaphores etc. Is there anything
similar in the Standard ANSI C++ or would I be best off doing this
myself, possibly creating a new class to handle any critical sections
and memory sharing etc.

Any articles on this subject are welcome as well.

Thanks.
 
G

Gavin Deane

Morpheus said:
Hi,

I have been coding in Windows for many years so have a mindset to it,
so forgive any stupid questions.

Is it possible to create a multithread application in C++ that is
portable (OS/compiler)? In my Windows applications, I use
synchronization objects like, mutex, semaphores etc. Is there anything
similar in the Standard ANSI C++ or would I be best off doing this
myself, possibly creating a new class to handle any critical sections
and memory sharing etc.

Any articles on this subject are welcome as well.

There is no support for threads or the kind of synchronisation objects
you mention in standard C++. However, before you write everything you
need from scratch, you might want to have a look at the threads library
in boost.

http://www.boost.org/doc/html/threads.html

See if it does what you want and if it is portable to the platforms you
care about.

Gavin Deane
 
M

mlimber

Morpheus said:
Is it possible to create a multithread application in C++ that is
portable (OS/compiler)? In my Windows applications, I use
synchronization objects like, mutex, semaphores etc. Is there anything
similar in the Standard ANSI C++ or would I be best off doing this
myself, possibly creating a new class to handle any critical sections
and memory sharing etc.

Any articles on this subject are welcome as well.

Check out this article on Boost.Threads:

http://www.ddj.com/dept/cpp/184401518

And you might be interested in this article on the future of threads in
standard C++:

http://www.artima.com/cppsource/threads_meeting.html

Cheers! --M
 
C

Chris Thomasson

Morpheus said:
Hi,

I have been coding in Windows for many years so have a mindset to it,
so forgive any stupid questions.

Is it possible to create a multithread application in C++ that is
portable (OS/compiler)? In my Windows applications, I use
synchronization objects like, mutex, semaphores etc. Is there anything
similar in the Standard ANSI C++ or would I be best off doing this
myself, possibly creating a new class to handle any critical sections
and memory sharing etc.

Any articles on this subject are welcome as well.

Here are some link to some relevant information:

http://groups.google.com/group/comp.lang.c/msg/81d30a778b43f2c5


http://groups.google.com/group/comp.arch/msg/c6f096adecdd0369
(refer to last part of the post...)


http://groups-beta.google.com/group/comp.programming.threads/msg/423df394a0370fa6





FWIW, I raise this issue in a very rough draft of a paper I am currently
working on. Here is a link to the crude draft:

http://appcore.home.comcast.net/vzdoc/atomic/static-init/



Its incomplete, however, what's there should be of interest to you...


Any thoughts?
 
P

Pete Becker

Morpheus said:
Is it possible to create a multithread application in C++ that is
portable (OS/compiler)? In my Windows applications, I use
synchronization objects like, mutex, semaphores etc. Is there anything
similar in the Standard ANSI C++ or would I be best off doing this
myself, possibly creating a new class to handle any critical sections
and memory sharing etc.

Any articles on this subject are welcome as well.

Thread-related proposals under discussion for the next C++ standard:

Concurrency memory model
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2052.htm

Thread-local storage
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1966.html

Atomic operations
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2047.html

Thread support
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1907.html
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2090.html


--

-- Pete

Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
 
P

P.J. Plauger

There is no support for threads or the kind of synchronisation objects
you mention in standard C++. However, before you write everything you
need from scratch, you might want to have a look at the threads library
in boost.

http://www.boost.org/doc/html/threads.html

See if it does what you want and if it is portable to the platforms you
care about.

Right. You can also get a commercial version of boost threads, already
ported to several major platforms, from us. But you might want to
check out Boost first. We also have documentation in the on-line manual
at our web site, for a quick overview.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
J

Joe Seigh

Pete said:

Since it's for the most part language adoption of Posix thread apis which
where established in the 90's, shouldn't it be called C++9x instead of
C++0x?

Seriously, the hardware is advancing at a faster rate than software
support for threading. This stuff won't scale for 100+ core processors.
This doesn't even begin to address the issues faced by techniques being
developed now. This is just language support for the last war so to
speak.
 
P

Pete Becker

Joe said:
Seriously, the hardware is advancing at a faster rate than software
support for threading. This stuff won't scale for 100+ core processors.
This doesn't even begin to address the issues faced by techniques being
developed now. This is just language support for the last war so to
speak.

I don't know how to write code that will scale to 100+ core processors,
much less what standard language support for it ought to look like. But
from the three-day special meeting we had in Redmond last month, which
included representatives from several hardware manufacturers as well as
people with far more experience writing multi-threaded code than I have,
I don't think anyone else does, either.

You're right that the papers pretty much stick to what's in existence
today. That's what language standards ought to do: standardize existing
practice. But note also that those papers are aimed at the next revision
of the C++ standard, which is pretty much feature-frozen now. There's
more going on, but it's targeted farther out in the future, and is still
somewhat speculative.

--

-- Pete
Roundhouse Consulting, Ltd. -- www.versatilecoding.com
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
 
J

Joe Seigh

Pete said:
Joe Seigh wrote:

You're right that the papers pretty much stick to what's in existence
today. That's what language standards ought to do: standardize existing
practice. But note also that those papers are aimed at the next revision
of the C++ standard, which is pretty much feature-frozen now. There's
more going on, but it's targeted farther out in the future, and is still
somewhat speculative.

I'm a little concerned since there doesn't seem to be any awareness of
some of the issues I've been running into. Being on the bleeding
edge isn't any fun when they move that edge out from under you and
you do a Wiley Coyote. I've had that happen to me in Java when they
revised the JVM specs and broke something I did that was legal in
Java 1.x. Fortunately I wasn't really using it but nevertheless.
 
M

mlimber

Joe said:
I'm a little concerned since there doesn't seem to be any awareness of
some of the issues I've been running into. Being on the bleeding
edge isn't any fun when they move that edge out from under you and
you do a Wiley Coyote.

That's the price of living on the bleeding edge. The stuff the standard
is concerned with is, as Pete said (cf. also the article I mentioned
elsethread), not on the bleeding edge precisely because the edge
changes so rapidly. Only common practice should be standardized, not
any of the myriad possible future practices.

Cheers! --M
 
G

Gianni Mariani

Pete said:

From the article:
.... Since the thread cannot then unlock the mutex, the result is a deadlock.

I have seen models where thread T1 can aquire a non-recursive mutex and
T2 can release the mutex. In some cases I have used that kind of
"transfer of aquisition of mutex" in real code. Sounds like the
"deadlock" semantics are nonsensical if there is a viable alternative.

I think also that the standard should be more specific about the use of
function statics. i.e.

void function()
{
static T t = expression;
}

If "function" is called simultaneously by 2 threads, expression should
be evaluated exactly once and if the initialization of t is being done
by "thread 1" then "thread 2" should wait until the initialization is
complete.

This is currently implied by the standard that says the initialization
of t must occur once but that requirement should be clarified in the
event of the standard becoming "thread aware". Plenty of discussion
around this "bug" can be found in the gcc bug list. I believe that
since gcc 4.0, it guarentees this for threaded code. I don't recall any
other compiler (besides gcc) guarenteeing this yet.

For gcc 4.0 and above, this is already a "call_once" construct with no
additional specification in the standard.

This in essence is a "once" function and eliminates the need for more
complexity in the "call_once" mechanism.

TSS is a very contentious issue since it seems to be used in different
ways by different people (experts) and hence raises all sorts of
conflicting requirements. TSS is already supported in gcc by the
__thread keyword as a storage specifier. I think this is the most
powerful model. This is the rationale. In the very few cases where I
have needed to use TSS, it has usually been where code is either legacy
or the application is for high performance. In the case of legacy code,
there is a variable (e.g. errno) which is being read/written to by
multiple threads simultaneously. In this case, converting the code to
be thread safe is simply a matter of declaring the variable "thread
specific" at which point the address of the variable is the same across
all threads but the variable is placed in a thread private page. This
is a very simple, reliable and "tested" model. The other case where TSS
is used when performance is an issue. It is very hard to argue that
from a performance perspective, depending on hardware support is the
solution of least overhead, also in almost all modern systems this type
of VM support is available. The con argument is that threads will have
objects that are not visible to one another and this is "bad", the
counter argument is that if this is not bad since if visibility is
required, you can still provide visibility like this:

T objects[MAXTHREADS];
__thread int my_thread_number = get_next_consecutive_thread_number();
__thread T & myobj = objects[ my_thread_number ];

This brings up a whole "thread segment" initialization and destruction
question for TSS. Nonetheless, this is something that is not too
unreasonable. If this is an issue, you could eliminate the question by
making a requirement that __thread objects are POD with no initializers
or non POD's TSS objects are allowed in function static variables only.
The intent of the code above still stands since this can be done in a
application specific thread initialization function.

This there is also the "thread once" concept which is like the
"call_once" concept raised, but it happens once per thread. This can be
achieved by this construct:

void function()
{
__thread static T t = expression;
}

Here, the "t" initializer is called once per thread.

The use of TSS in practice is very limited. In the past I have used it
to create very fast thread primitives and in the case where from an API
perspective I needed an application context in a high performance legacy
graphics application that was needed a thread specific context to
implement a "multi threaded" rendering architecture. Hence, use of TSS
should only be needed in very very few cases but where it is needed it
is probably accompanied by the need for tight performance as well.

On the issue of condition variable "spurious wakeup". Someone please
explain to me why the condition variable implementation can't fix this
problem. In all the thousands of condition variable tests I have done,
I don't think I have ever detected a "spurious" wakeup. This should
just be "fixed" as complicating the usage for programmers is just asking
for trouble. Also, as part of the win32 condition variable
implementations I have seen, I don't think it was possible to have a
"spurious" wake up. I suggest that it is not acceptable to have
"spurious" wake up as part of the standard. That still does not mean
the suggestion in the article that the condition should not be check is
a good one, but that should be an application specific issue.

....

There should be a "convenience class" that is a mutex and condition
variable i.e.:

class condition_mutex
: public mutex,
public condition
{ ... };

90 % of the cases, this is what is used and makes the API straight
forward for most cases. This then begs the question of "why all these
mutex types" ? (i.e. mutex, tr_mutex, timed_mutex, recursive_mutex,
etc). In the Austria API, there is one mutex type that can be tweaked
at initialization.

....

The "islock()" method is asking for trouble. In a threaded environment,
this is next to useless since by the time "islock" returns, it is quite
possible that the return value does not reflect the nature of the lock,
this should be replaced with a "trylock".

If I understand the mutex api, it appears that I can't "try lock" on a
regular mutex ? I don't think there is any practical reason to do this.
A regular mutex should have a "trylock" method.

....

thread::cancel is notoriously difficult to use properly. I would
suggest to avoid the whole "cancel" thread idea. I would say it is the
application's responsibility to provide a safe way to "terminate early"
as only the application is able to tell if it has left a consistent
state behind if it leaves.

Managing "thread lifetime" and "object lifetime" is critical, the rule
should be that the lifetime of the thread cannot be longer than the
lifetime of the threads "primary" object. By looking at the "create"
API I can't tell if this can be enforced. My experience with the
Austria C++ "Task" API (which incidentally is concept is similar to the
ACE task api), is that combining of the "join on destruct" forces a
paradigm than minimizes programmer errors yet does not relinquish any
"power of the API".

....

There is a craete() API implied race condition between thread creation
and the thread handle being "known". In the case of the at::Task API,
this race condition is impossible because by the time the thread starts
executing application code, the handle is known. In the case of the
proposed thread API, the thread handle is not known until the thread has
already potentially run amok.

Which brings me to the rule: Asynchronous apis cannot return values
reliably. Or said in a practical way, "Never return a value from an
asynchronous API".

....

These comments are just from a cursory look at the boost API. I think
there are some serious deficiencies in this proposed thread API and I'd
like to see some more analysis before it gets committed to the standard.

/g
 
G

Gianni Mariani

Joe said:
Pete Becker wrote: ....

Seriously, the hardware is advancing at a faster rate than software
support for threading. This stuff won't scale for 100+ core processors.
This doesn't even begin to address the issues faced by techniques being
developed now. This is just language support for the last war so to
speak.

Very very few applications need to run on 100+ cores. So the question
that needs to be asked is "why make a complex problem even harder for
the benefit of the very very few" ?

OS/vendor specific extensions are probably not going to be easily
standardizabe. C++ really does need a standard thread model. Almost
any application I write today needs thread support. So this leads to a
question for you, (Joe). If there is a standardizable and simple subset
of the functionality that you would like to see in the standard, what is
it ?

Traditionally, thread API's have been too relaxed, allowing programmers
to shoot themselves far too easily. If anything I would like to see an
API that makes it difficult for a programmer to make mistakes or that
mistakes can be easily seen by looking for deviations from convention.
My experience with the Austria C++ thread support is that less
experienced programmers don't make the same stupid mistakes that I made
15 years ago and that when they do it's trivial (or easier) to find the
cause of the deadlock or race condition. With the projects I have been
involved in with the Austria C++ API at least, the problems due to race
conditions/bad code have been very far and few between.

I'm not saying that Austria C++ is the best thing ever. I'm just trying
to point out that the conventions implied by the at::threads interface
lead to fewer programmer errors. To me, minimizing the complexity of MT
code is probably the most valuable thing you could do to C++ and MT
programming in general.
 
G

Gianni Mariani

mlimber said:
Joe Seigh wrote: ....

That's the price of living on the bleeding edge. The stuff the standard
is concerned with is, as Pete said (cf. also the article I mentioned
elsethread), not on the bleeding edge precisely because the edge
changes so rapidly. Only common practice should be standardized, not
any of the myriad possible future practices.

Let's not shoot Joe down. I'd love to see what Joe is talking about and
if it makes sense, there is no reason why it should not be considered.
Joe, speak your mind. What do you want ?
 
G

Gianni Mariani

Morpheus said:
Hi,

I have been coding in Windows for many years so have a mindset to it,
so forgive any stupid questions.

Is it possible to create a multithread application in C++ that is
portable (OS/compiler)? In my Windows applications, I use
synchronization objects like, mutex, semaphores etc. Is there anything
similar in the Standard ANSI C++ or would I be best off doing this
myself, possibly creating a new class to handle any critical sections
and memory sharing etc.

Any articles on this subject are welcome as well.

I have published the Austria C++ library that provides linux/posix and
win32 thread support.

An older version is available on the source forge website.

A draft of a newer one is available from:

http://netcabletv.org/public_releases/

The draft tar/bzip file is about 100 megs (contains some prebuilt
binaries) and third party support libraries as well.

/g
 
J

Joe Seigh

Gianni said:
Let's not shoot Joe down. I'd love to see what Joe is talking about and
if it makes sense, there is no reason why it should not be considered.
Joe, speak your mind. What do you want ?
One of the most powerful features of C/C++ is that it doesn't prevent you
doing things that aren't explicitly supported by the language. You
can't really say that about other languages. In Java you have to
modify the language, the JSP process usually, and the stuff that
goes in was orginally prototyped in C for the most part. I don't
know what will happen if you are no longer able to prototype and
experiment in C/C++. Assembler or writing you own compiler maybe?

The importance of the bleeding edge stuff isn't so much that you
have to support it now as much at not excluding it as a possibility
in the future.

Some examples. The atomics stuff is fairly conservative for the
sake of portability. This is a problem since some lock-free depends
on some of the more specialized instructions like double wide compare
and swap. If you don't have support for that, you might as well have
no support since anyone needing that has to resort to supplying their
own atomics. They should be provided as conditional features. It's
not clear from the atomics document whether they intend to do this.
Also note that simulating compare and swap using load locked/store
conditional doesn't make up for not providing the latter as an api.
I have algorithms that either need double wide compare and swap or
load locked/store conditional. A simulated single wide compare and
swap won't work.

An attribute to restricting to thread local storage (stack or register).
Something like the register attribute but mandatory, and not limited
to registers obviously. There's a number of lock-free schemes out there
besides mine that need to distinguish between local storage and global
shared storage to ensure correct usage.

Better smart pointer abstraction and support. Templates don't really
hack it. I don't know where it's going so I can't say exactly what
has to be done now. The gc finalizer vs. delete is nothing compared
to some of the stuff I'm seeing. And I still think new and delete are
defined in the wrong place. They should be part of the smart pointer
definition, not the referenced class.

Again, nothing has to be done now but a little more awareness of the
more experimental stuff would be nice.
 
P

Pete Becker

Joe said:
One of the most powerful features of C/C++ is that it doesn't prevent you
doing things that aren't explicitly supported by the language. You
can't really say that about other languages. In Java you have to
modify the language, the JSP process usually, and the stuff that
goes in was orginally prototyped in C for the most part. I don't
know what will happen if you are no longer able to prototype and
experiment in C/C++. Assembler or writing you own compiler maybe?

Standardizing thread support does not prevent you from doing just what
you've been doing. You're not required to use the new facilities. You'll
still be able to prototype and experiment in C and C++.

--

-- Pete
Roundhouse Consulting, Ltd. -- www.versatilecoding.com
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
 
J

Joe Seigh

Pete said:
Standardizing thread support does not prevent you from doing just what
you've been doing. You're not required to use the new facilities. You'll
still be able to prototype and experiment in C and C++.

It's not the new facilities I worried about. It's about whether the
old undocumented capabilities get broken or not. It happens all the
time with programs depending on unspecified behavior. And since C/C++
currently does not support threading, all threaded programs depend on
unspecified behavior to a certain extent. How much might get broken
depends on how aware the C++0x architects are of the range of
threaded applications out there. If they manage not to break anything
that will be the first time in the history of computing that has
happened.
 
P

Pete Becker

Joe said:
It's not the new facilities I worried about. It's about whether the
old undocumented capabilities get broken or not.

Sorry, no sympathy. If you're relying on undocumented behavior you're at
the mercy of your compiler and OS vendor, regardelss of what any
standards say. If they change undocumented behavior in ways that you
don't like, complain to them.

--

-- Pete
Roundhouse Consulting, Ltd. -- www.versatilecoding.com
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
 
J

Joe Seigh

Pete said:
Sorry, no sympathy. If you're relying on undocumented behavior you're at
the mercy of your compiler and OS vendor, regardelss of what any
standards say. If they change undocumented behavior in ways that you
don't like, complain to them.

It's only experimental code, not production code. It's mostly for
seeing how well lock-free performs and scales compared to lock based
synchronization.
 
P

Pete Becker

Joe said:
It's only experimental code, not production code. It's mostly for
seeing how well lock-free performs and scales compared to lock based
synchronization.

Just for your reassurance, there's been a great deal of discussion of
lock-free programming (far too much for my comfort, since it's so
fragile -- definitely not for beginners) in the course of developing the
plans for thread support in the next standard.

--

-- Pete
Roundhouse Consulting, Ltd. -- www.versatilecoding.com
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." For more information about this book, see
www.petebecker.com/tr1book.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top