Sunday, July 26, 2015

Digest for comp.lang.c++@googlegroups.com - 14 updates in 6 topics

legalize+jeeves@mail.xmission.com (Richard): Jul 26 09:05PM

[Please do not mail me a copy of your followup]
 
Doug Mika <dougmmika@gmail.com> spake the secret code
 
>struct std::tm * ptm = std::localtime(&tt);
 
This is basically a C-ism and the 'struct' is unnecessary in C++.
 
In C, without a typedef you have to say 'struct foo' all the time to
refer to the name 'foo' as the name of a structure. This is why you
often see this in C:
 
typedef struct tag_foo foo;
 
or this
 
typedef struct tag_foo {
int member;
} foo;
 
In C, you can't write:
 
struct foo {
int member;
};
 
foo *p = (foo *) malloc(sizeof(foo));
 
Instead you must either introduce a typedef or you must write:
 
struct foo *p = (struct foo *) malloc(sizeof(struct foo));
 
This code is perfectly legal in C++, but the use of 'struct' is
redundant here because C++ introduces new names for types whenever
they are declared with struct, union, or class.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Jul 26 08:47PM

[Please do not mail me a copy of your followup]
 
Robert Wessel <robertwessel2@yahoo.com> spake the secret code
 
>The OP's original code was shifting signed integers as well.
 
The formatting made it pretty hard to read, but the input variable was
of type 'uint64_t y'. The problem was that they didn't use this
directly and instead went through some crazy loopping over int's that
were shifted around.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
ram@zedat.fu-berlin.de (Stefan Ram): Jul 26 04:09PM

>I have copied this from a books eratta list. Should the code with
>operator= not be (i1.operator=(i2)).operator=(i3); ?
 
Yes, »eratta« should be written »errata«, and the code
equivalent to »(i1 = i2) = i3« should be written as
»(i1.operator=(i2)).operator=(i3)«.
Fraser Ross <fraser.ross8ATbtinternet.com@com>: Jul 26 04:25PM +0100

I have copied this from a books eratta list. Should the code with
operator= not be (i1.operator=(i2)).operator=(i3); ?
 
int i1,i2,i3;
It turns out that "(i1 = i2) = i3;" yields undefined results when i1,
i2, and i3 are ints, because i1 is modified more than once without an
intervening sequence point. This is not a problem for user-defined
types, because for such types, the above is be equal to
i1.operator=(i2.operator=(i3)); and that's fine, because there's a
sequence point before and after each function call.
 
 
 
Fraser.
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jul 26 11:39AM +0200

On 25.07.15 20.58, Doug Mika wrote:
> //cout<<"main thread going to sleep"<<endl;
> while (!t1Ready||!t2Ready) {
> cout<<"."; //IF YOU DELETE THIS cout, THE PROGRAM DOESN'T WORK!!
 
Indeed. Your booleans are not declared to be changed asynchronously. So
the compiler may optimize away the entire loop and check the condition
only once. And even if the compiler will not do this kind of
optimization you are missing a memory barrier, i.e. the CPU cache of the
executing thread might return out-dated values.
 
This changes by the call to cout<<. First of all any function call might
change any static variable unless it is an inline function and the
compiler knows its code. So calling a function from another object
module implicitly acts like volatile here.
 
Secondly the iostreams are thread-safe (nowadays guaranteed), i.e.
writing to the same stream from different threads is defined behavior in
the way that it will not turn the stream into an inconsistent state and
no output is lost. (Note that the order of the output is still undefined.)
However, this thread safety is usually implemented by a mutex. So each
call to operator<< acquires and releases a mutex at least once. The
mutex operations in turn imply a full memory barrier. So the CPU cache
is also synchronized. That't the reason why it works.
 
This is also why others recommended atomic_bool.
 
volatile in contrast is /not sufficient/ as it solves the optimization
problem but not the memory fence for cache coherence. Although on
typical hardware the caches become synchronized somewhat later. So your
detection is usually only delayed undefinedly.
 
But besides all the discussion above I would reject this code as soon as
I see it anywhere because of the busy loop that constantly eats CPU
cycles without any reasonable result. A wait() is missing in this loop.
I would not even accept this for educational purposes unless the task is
to demonstrate what happens because of the wrong code.
 
 
Marcel
Bo Persson <bop@gmb.dk>: Jul 26 11:50AM +0200

On 2015-07-26 11:39, Marcel Mueller wrote:
> change any static variable unless it is an inline function and the
> compiler knows its code. So calling a function from another object
> module implicitly acts like volatile here.
 
This is very much like using volatile - not sufficent. :-)
 
Modern compilers are smart enough to inline functions from other
modules, so they surely can see the code there as well.
 
So the "trick" here is that cout either contains some synchronization,
or makes operating system calls, which compilers cannot see through (yet).
 
> problem but not the memory fence for cache coherence. Although on
> typical hardware the caches become synchronized somewhat later. So your
> detection is usually only delayed undefinedly.
 
 
Bo Persson
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jul 26 11:52AM +0200

On 26.07.15 00.48, Chris M. Thomasson wrote:
 
> :^)
 
> For use in threading, it can actually backfire to the point where it
> blows the damn car up.
 
Full ack!
 
In C++ (unlike C#) volatile does not force acquire / release semantics
an read / write access to volatile fields. So it is of very limited use.
 
The only use I remember is to declare class instances as volatile, but
only for the purpose to invoke other thread-safe member function
overloads. This can be very useful for strongly thread safe, reference
counted smart pointers or string classes.
 
 
Marcel
Wouter van Ooijen <wouter@voti.nl>: Jul 26 02:08PM +0200


> The only use I remember is to declare class instances as volatile, but
> only for the purpose to invoke other thread-safe member function
> overloads.
 
You are under-appreciating voltaile! *Everything* you do in an
application is ultimately communicated to the outside world by
manipulating volatile variables that represent hardware registers that
are somehow electrically coupled to I/O hardware. Without volatile your
application would be totally deaf-mute.
 
Wouter
Luca Risolia <luca.risolia@linux-projects.org>: Jul 26 02:52PM +0200

Il 26/07/2015 14:08, Wouter van Ooijen ha scritto:
> manipulating volatile variables that represent hardware registers that
> are somehow electrically coupled to I/O hardware. Without volatile your
> application would be totally deaf-mute.
 
volatile and atomic<> are orthogonal. For example, it would not be
unreasonable to use them together in device drivers that need to access
special I/O memory concurrently:
 
volatile atomic<int> val; // atomic, no reorderings, no optimizations.
pedro1492@lycos.com: Jul 25 06:24PM -0700

I came across this with 3 parameters
 
void Interpwrap::setConvFunc (InterpConvFunc func, void *obj2, int num_bytes)
{
_conv_func = func;
_conv_obj2 = obj2;
_conv_val_len = num_bytes;
}
 
The only call anywhere in package has 2 arguments
 
setConvFunc (defaultConvFunc, this);
 
num_bytes is defined as 4 in a header file.
With a 64-bit compiler (gcc, Intel or open64) _conv_val_len ends up as 8.
Okay with 32-bit compilers.
What happened?
JiiPee <no@notvalid.com>: Jul 26 02:47AM +0100

> With a 64-bit compiler (gcc, Intel or open64) _conv_val_len ends up as 8.
> Okay with 32-bit compilers.
> What happened?
 
I guess people need to see more code to know what happened. maybe there
are some defines or something...
bartekltg <bartekltg@gmail.com>: Jul 26 04:01AM +0200


> The only call anywhere in package has 2 arguments
 
> setConvFunc (defaultConvFunc, this);
 
> num_bytes is defined as 4 in a header file.
 
this has nothing to do with the problem. In method you create
new variable with the same name.
 
> With a 64-bit compiler (gcc, Intel or open64) _conv_val_len ends up as 8.
> Okay with 32-bit compilers.
> What happened?
 
Are you sure there isn't a second, overloaded version?
If you use semi decent IDE, you can click on a call to function
(a function name in the line
setConvFunc (defaultConvFunc, this); )
and under context menu there should be something
like 'follow symbol under cursor F2'.
 
bartekltg
Melzzzzz <mel@zzzzz.com>: Jul 26 04:21AM +0200

On Sun, 26 Jul 2015 04:01:36 +0200
> > as 8. Okay with 32-bit compilers.
> > What happened?
 
> Are you sure there isn't a second, overloaded version?
 
Could be also default argument declared in header...
Victor Bazarov <v.bazarov@comcast.invalid>: Jul 26 08:46AM -0400

> With a 64-bit compiler (gcc, Intel or open64) _conv_val_len ends up as 8.
> Okay with 32-bit compilers.
> What happened?
 
Look at the declaration of that member in 'Interpwrap' class.
 
V
--
I do not respond to top-posted replies, please don't ask
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: