Re: Multi-threaded C++ programs: wrought with peril?
- From: "Tom Widmer [VC++ MVP]" <tom_usenet@xxxxxxxxxxx>
- Date: Mon, 15 Jan 2007 14:09:30 +0000
Joe wrote:
Marc Sherman wrote:As long as the thread synchronization API's are used (eg. WaitForXXX,
InterLockXXX, etc.), why would faith be needed?
Technically, those apis don't mean anything to C++, so the compiler is
free to reorder as it wills. That is if we have (I don't feel like
looking up the exact apis so I will use lock() unlock() and increment()
):
for (int ix = 0; ix < 10; ++ix)
{
lock();
increment(count);
unlock();
}
the compiler is free to generate code as if you had written:
increment(count, 10);
for (int ix=0; ix < 10; ++ix)
{
lock();
unlock();
}
Another example (which doesn't require the optimizer to reorder OS API calls):
for (int ix = 0; ix < 10; ++ix)
{
lock();
++count;
unlock();
}
could be modified to:
count += 10;
for (int ix = 0; ix < 10; ++ix)
{
lock();
unlock();
}
if the compiler could prove that lock and unlock don't access count. The faith is really about the fact that you have to "assume" that the compiler isn't smart/stupid enough to see that lock and unlock don't affect count (which they don't directly, of course), and thus reorder things.
You can see how that might mess up a multithreaded program.
Fortunately, the microsoft compiler won't do hoisting when locks are
involved (I don't think anyway), so it isn't a problem, but there is
nothing in the C++ standard guaranteeing that. It's really the same
thing with the double checked locking algorithm. Without some
guarantees from the compiler (or a sufficiently non-optimizing
compiler), one of the checks can be removed by the optimizer and things
break.
The faith comes in that the compiler won't do optimizations when
locking apis are in use. One problem is that it can be hard to
determine if locking apis are being used. If you wrap the apis in a
class, then it can be hard for the compiler to see them. I suppose
most use inline code for their wrappers, but it's conceivable that
someone is using a seperately compiled class as a wrapper. In that
case, the compiler may not know that it shouldn't hoist code out of
loops.
Fortunately (for multithreaded code), the compiler is generally unable to do any hoisting of potentially thread shared variables (e.g. globals and potentially aliased variables) at all through OS API calls, due to the fact it can't see into the API calls and therefore doesn't know whether they might access those variables, or whether the API calls contain any observable behaviour. For the same reason, it usually can't reorder OS API calls. e.g.
extern int i;
i = 10;
api1();
i = 11;
api2();
print(i);
Since the compiler doesn't know whether api1 or api2 might access i, it can't optimize any of the writes to i. At least, I have "faith" that this is the case.
Two more examples:
int i = 10; //i is a local variable
api1();
i = 11;
api2();
print(i);
Here, the compiler can change it to:
api1();
api2();
print(11);
since it is clearly impossible for api1 and 2 to access i.
Finally:
int i = 10;
api1(&i);
i = 11;
api2();
print(i);
Here, no i optimization is possible again, due to the fact that i may be aliased.
Tom
.
- References:
- Multi-threaded C++ programs: wrought with peril?
- From: John
- Re: Multi-threaded C++ programs: wrought with peril?
- From: Tom Widmer [VC++ MVP]
- Re: Multi-threaded C++ programs: wrought with peril?
- From: Marc Sherman
- Re: Multi-threaded C++ programs: wrought with peril?
- From: Joe
- Multi-threaded C++ programs: wrought with peril?
- Prev by Date: Re: Multi-threaded C++ programs: wrought with peril?
- Next by Date: Re: How to eject removable devices programmatically?
- Previous by thread: Re: Multi-threaded C++ programs: wrought with peril?
- Next by thread: Re: Multi-threaded C++ programs: wrought with peril?
- Index(es):
Relevant Pages
|