Wednesday, August 26, 2015

Digest for comp.lang.c++@googlegroups.com - 24 updates in 3 topics

Christopher Pisz <nospam@notanaddress.com>: Aug 26 12:06PM -0500

On 8/25/2015 3:34 PM, Chris Vine wrote:
> the boost documentation, I see also according to boost). In your code
> the destructor of SomeClass calls join() on m_thread and any thread
> calling your SomeClass::Join() method will do the same.
 
But the destructor should only occur on the main thread. The class
doesn't enforce that, but that's the intention.
 
 
> By the time the
> destructor of SomeClass is entered and calls join() any thread blocking
> on SomeClass::join() will probably have returned
 
join should also only occur on the main thread. The class doesn't
enforce that, but that's the intention.
 
> your clients, so be it. If you are concerned with portability and
> standard compliance you would use a condition variable, or remove your
> SomeClass::Join() function.
 
I don't see how I would go about using a condition variable to replace
the fact that the parent thread has to join its child threads. What
would be the condition I am waiting on? What would I do after the
condition is met?
 
Would the condition be waiting on all child threads to exit? I'm not
sure how to set that up... while the interrupt signals them to exit?
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Aug 26 09:01PM +0100

On Wed, 26 Aug 2015 12:06:11 -0500
Christopher Pisz <nospam@notanaddress.com> wrote:
[snip]
> > same.
 
> But the destructor should only occur on the main thread. The class
> doesn't enforce that, but that's the intention.
 
See below.
 
> > blocking on SomeClass::join() will probably have returned
 
> join should also only occur on the main thread. The class doesn't
> enforce that, but that's the intention.
 
You cannot call join() in different threads, and you cannot call
join() twice in the same thread. A thread ceases to be joinable after
it has ended and at some short unspecified time before join() returns.
Calling join() on an unjoinable thread generates undefined behaviour,
whether it is a different thread from the one which previously called
join(), or the same one.
 
> replace the fact that the parent thread has to join its child
> threads. What would be the condition I am waiting on? What would I do
> after the condition is met?
 
The condition you are waiting on is the thread ending. The last thing
the thread function does (or a wrapper around the thread function does)
is to set an "ended" flag true and broadcast on the condition
variable. Waiting threads will then unwake, see from the flag that the
thread has ended and carry on doing what you want them to do in those
circumstances.
 
std::thread::join() is trivially replaceable by a condition variable
wait. In fact, if you can bear looking at the POSIX documentation
there is a discussion about it and why they bothered with
pthread_join() at all. C++11 threads are a direct transposition of
POSIX threads, as I am sure you have noticed.
 
I think from other posts of yours that you are a windows programmer, and
if so isn't that what you have to do with windows threads? Don't you
call WaitForSingleObject on the thread handle (which incorporates its
own event object). Presumably you must have done this stuff before with
windows threads, so just do the same with a condition variable.
 
Doing it with a condition variable has the advantage that (a) any
number of threads can block on it, and (b) any thread can test the
condition as many times as you want without undefined behaviour.
 
> Would the condition be waiting on all child threads to exit? I'm not
> sure how to set that up... while the interrupt signals them to exit
 
Using a condition variable also allows you to wait on more than one
thread to finish with only the single variable. Just set that as your
condition.
 
This approach, or using join(), will join on the ending of a thread
(or the threads) whether it/they end in response to your interrupt or
for some other reason. That is presumably what you want. (In any
event, as you know I am suspicious of your interrupt code: it is
difficult to get interrupts and threads to work well together.)
 
I may have misunderstood what you are doing again in which case I
return to my view that your code is unnecessarily convoluted.
 
Chris
Christopher Pisz <nospam@notanaddress.com>: Aug 26 03:38PM -0500

On 8/26/2015 3:01 PM, Chris Vine wrote:
> variable. Waiting threads will then unwake, see from the flag that the
> thread has ended and carry on doing what you want them to do in those
> circumstances.
 
Ok, maybe, it doesn't matter if the thread actually ended/returned as
long as the condition flipping was the last thing that happened?
 
I seem to recall some crash occuring because the condition was flagged
before the function actually returned, but I don't remember the details.
 
I will retry another example using std::thread.
 
 
> call WaitForSingleObject on the thread handle (which incorporates its
> own event object). Presumably you must have done this stuff before with
> windows threads, so just do the same with a condition variable.
 
I program on Windows, but I am none too happy with the Window's API and
have managed to stay away from Windows Thread functions, since boost
1.32 or so. I can't even remember what I did before that. It's been
fairly infrequent on needed to go rearchitect some single threaded work
into multithreaded work and it is one of those things that once it's
done and it works, you don't look at it again...like calculus in college.
 
 
> Using a condition variable also allows you to wait on more than one
> thread to finish with only the single variable. Just set that as your
> condition.
 
I don't know how to set up a condition of "When all 10 threads are done,
you are flagged" with a single condition variable. Is there an example
somewhere?
 
 
> for some other reason. That is presumably what you want. (In any
> event, as you know I am suspicious of your interrupt code: it is
> difficult to get interrupts and threads to work well together.)
 
I am just trying to get ctrl-c, console program exit. I pretty much want
the threads to run until program shutdown. In the real world this will
be when the windows service stops.
 
> I may have misunderstood what you are doing again in which case I
> return to my view that your code is unnecessarily convoluted.
 
I just want to start some variable number of worker threads from program
startup and have them do some chore that can be defined by a derived
class, until program exit.
 
The only difference between my goal and the most trivial thread examples
on the internet are that I want to encapsulate the function being run by
a worker thread as a method in a class.
 
Such that I could make a class "file processor" that takes a filename,
and reads the file on its own thread. Or more realistically, a thread
that gets customer data, processes it, and sends it to another system
component periodically in a loop until shutdown.
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Aug 26 10:07PM +0100

On Wed, 26 Aug 2015 15:38:00 -0500
> > them to do in those circumstances.
 
> Ok, maybe, it doesn't matter if the thread actually ended/returned as
> long as the condition flipping was the last thing that happened?
 
It should not make any difference, provided setting its flag
and then broadcasting on the condition is the last thing the thread
does.
 
> flagged before the function actually returned, but I don't remember
> the details.
 
> I will retry another example using std::thread.
 
It occurs to me that if you can guarantee as an invariant that all
calls to join() are made in a single thread, you could precede the call
to join() with a test of joinable(), which would avoid any undefined
behaviour. However, having such an invariant would run the risk of
making your code very brittle.
 
[snip]
 
> I don't know how to set up a condition of "When all 10 threads are
> done, you are flagged" with a single condition variable. Is there an
> example somewhere?

You give each thread an "end" flag and, as the condition applied to the
variable on which your waiting thread is waiting, you test that each of
the flags is set to true. If not, loop and carry on waiting. Whether
this does what you want I am not sure because I have not got a clear
enough view of the strategic objective.
 
Chris
Prroffessorr Fir Kenobi <profesor.fir@gmail.com>: Aug 26 12:40PM -0700

Im using tdm gcc compilers to compile my winapi projects, when i test some simple mandelbrot sse
code 9maybe with other projests its like the same but i not tested everything), 5.1 generates larger executable 330kB against 270kB (though i not recompiled everything, only hot loop module and linked with already compiled (in 4.7) ones)
and also noticalby slower code 23.5 ms /frame agianst 20 ms in 4.7
 
it is scary.. what can i do with it? (the rest of settings etc is the same i only rename the compiler folder from one to anither
 
(If co maybe i should download the whole variety of 10 versions and check which one is the best :C,
as i said this is scary to me)
Bo Persson <bop@gmb.dk>: Aug 26 10:16PM +0200

On 2015-08-26 21:40, Prroffessorr Fir Kenobi wrote:
 
> it is scary.. what can i do with it? (the rest of settings etc is the same i only rename the compiler folder from one to anither
 
> (If co maybe i should download the whole variety of 10 versions and check which one is the best :C,
> as i said this is scary to me)
 
In this case I would recompile everything, and not blame the speed on
the new compiler if some code is compiled with the old compiler.
 
Perhaps the optimizer doesn't work well with the mix?
 
 
Bo Persson
Prroffessorr Fir Kenobi <profesor.fir@gmail.com>: Aug 26 01:44PM -0700

W dniu środa, 26 sierpnia 2015 22:16:35 UTC+2 użytkownik Bo Persson napisał:
 
> In this case I would recompile everything, and not blame the speed on
> the new compiler if some code is compiled with the old compiler.
 
> Perhaps the optimizer doesn't work well with the mix?
 
well alright, i can recompile (got separate compile scripts in large numnber but can do it in few minutes), but i doubt..
Prroffessorr Fir Kenobi <profesor.fir@gmail.com>: Aug 26 01:52PM -0700

W dniu środa, 26 sierpnia 2015 22:44:52 UTC+2 użytkownik Prroffessorr Fir Kenobi napisał:
> > the new compiler if some code is compiled with the old compiler.
 
> > Perhaps the optimizer doesn't work well with the mix?
 
> well alright, i can recompile (got separate compile scripts in large numnber but can do it in few minutes), but i doubt..
 
allright checked.. nothing changes.. the main module with the mandelbrot code is fundamental as on those 23.5 ms it consumes 23 ms
 
I notice also that when compiling mofules with 5.1 modules .o seem 1k bigger (each one),
 
could disassemble maybe and inspect it for both versions, though im bit tired now, so maybe toomorrow
Prroffessorr Fir Kenobi <profesor.fir@gmail.com>: Aug 26 02:06PM -0700

ps i made yet quick test
 
as i may compile loop module in 51 and link all in 47
 
compile loop 47 link 47: size 270k speed 20 ms
 
compile loop 51 link 51: size 330k speed 23.5 ms
 
compile loop 47 link 51: size 330k speed 20 ms
 
compile loop 51 link 47: size 270k speed 23.5 ms
 
it shows that speed drop comes by compile in 51
and size bloat comes from link 51
"Öö Tiib" <ootiib@hot.ee>: Aug 25 11:37PM -0700

On Tuesday, 25 August 2015 22:32:23 UTC+3, David Brown wrote:
 
> This is getting /way/ outside my level of C++ (I don't actually do much
> C++ at the moment, and when I do it is mostly on embedded systems - and
> exceptions are disabled entirely).
 
I have also used C++ mostly for embedded development for more than year now
in latest new projects (some sort of peak of embedded development?).
Exceptions being disabled is often the case but not always and it is
pointless for PC or for mobile device applications.
 
> exceptions down the chain. The extern "C" merely means there is no name
> mangling (thus no overloading or default parameters), and may
> conceivably alter calling conventions.
 
Yes that all is so to my knowledge as well. I just have position/opinion
that it is not good since extern "C" is mainly meant for interfacing
with modules not written in C++. How can such handle (or even expect)
C++ exceptions thrown from a supposedly C interface? So most intuitive
would be the functions defined extern "C" to be 'noexcept(true)'
implicitly.

 
> But as said, I am far from sure on this - hopefully someone more
> knowledgeable will make things clear.
 
In practice visual studio has command line options to set it one or other
way, gcc and clang are awfully vague about it and mine coding standard is
that throwing from extern "C" function is defect regardless what standard
tells.
Juha Nieminen <nospam@thanks.invalid>: Aug 26 08:11AM

> the non-virtual case is:
> Foo_Whatever(obj, ...);
 
The point is that a "generic" data container in C can't make that kind of
call (because there's no function overloading in C.)
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
Wouter van Ooijen <wouter@voti.nl>: Aug 26 10:12AM +0200

> C++ exceptions thrown from a supposedly C interface? So most intuitive
> would be the functions defined extern "C" to be 'noexcept(true)'
> implicitly.
 
That extern C function can easily call a C++ function (by name when it
is declared extern "C", or by passing it a function pointer), which can
raise an exception.
 
Wouter van Ooijen
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Aug 26 10:20AM +0100

On Wed, 26 Aug 2015 10:12:49 +0200
 
> That extern C function can easily call a C++ function (by name when
> it is declared extern "C", or by passing it a function pointer),
> which can raise an exception.
 
Function pointers also have language linkage. It affects things like
the calling convention. If the interface in question expects to be
given function pointers to C functions then the function pointers should
be declared extern "C" if passed by a C++ program.
 
You cannot as a rule propagate exceptions across language boundaries.
A C library will know nothing about C++ exceptions.
 
There is however limited support by particular compilers for passing
C++ exceptions through functions with C language linkage in C++
programs. gcc allows it if the function with C language linkage is
compiled with the -fexceptions compiler option (this allows C++
exceptions to traverse the C stack frames). I believe that MSVC will
do something similar, and also enables C code to catch C++ exceptions
in a limited fashion.
 
Chris
Juha Nieminen <juha.nieminen@gmail.com>: Aug 26 03:27AM -0700

On Tuesday, August 25, 2015 at 11:28:28 AM UTC+3, jacobnavia wrote:
> > which structs require manual construction and destruction, and which don't.
 
> It is very simple. When you are finished with a container you should
> call its Finalize method.
 
You don't understand.
 
If you have something like "Container cont;" you have to destroy it manually.
 
If you have something like "struct A { Container cont; };" you now have to
make sure that every time you instantiate that struct, you construct and
destroy its member appropriately (and of course manually.)
 
If you have something like "struct B { struct A a1, a2; };" you now have to
also make sure to construct and destroy those members appropriately whenever
you use B (which isn't at all apparent from that declaration alone, as there is no indication that you need to do that.)
 
Moreover, and more damningly, if struct A did *not* have the generic data
container as a member originally, and there is a lot of code using B, and
then later you add the generic data container to A, now you would need to
go through all the code that uses B and A, and make sure that they are
always constructed and destroyed appropriately (something that's extremely tedious, time-consuming and error-prone.) Imagine millions of lines of code
using struct B, all of which you would now need to refactor, just because
you wanted to add a dynamic data container into struct A. Much of that code
using struct B might in in a form that's very laborious to refactor into
a form that makes sure that the containers are destroyed appropriately.
 
And these are extremely simplistic examples. In actual programs the data
structure hierarchies can become a lot more complicated.
 
Needless to say, none of this is necessary in C++. If you change C to contain
some generic data structure, none of the code using X needs to be changed
accordingly.
 
> > can be. It's one of the biggest sources of bugs in C programs out there.
 
> Yes but this is the price to pay to avoid C++ complexity that is also a
> source of many bugs.
 
So you are replacing complexity with complexity.
 
Thanks, but no thanks.
 
> > And debugging macro-based dynamic data containers must be a joy.
 
> It is. The source code is available and easy to debug.
 
You don't even understand what I'm saying, do you?
 
We have a serious case of dogma here, it seems.
Johannes Bauer <dfnsonfsduifb@gmx.de>: Aug 26 12:27PM +0200

On 24.08.2015 14:06, Juha Nieminen wrote:
 
> It's impossible for C++ to be slower than C, given that (almost) any
> valid C program is also a valid C++ program. (Those "almost" exceptions
> are not things that affect speed, mainly only syntax.)
 
That is a *really* cheap cop-out. Basically what you're saying is: "C++
is as fast as C if we leave out everything C++ish and just rely on C."
 
But that's not the point. Then you're writing C and compiling it with a
C++ compiler.
 
The point would be to have better language constructs perform the same
task in a more maintainable/readable/object-oriented fashion while STILL
being as fast as C.
 
Cheers,
Johannes
 
--
>> Wo hattest Du das Beben nochmal GENAU vorhergesagt?
> Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <hidbv3$om2$1@speranza.aioe.org>
Juha Nieminen <juha.nieminen@gmail.com>: Aug 26 03:33AM -0700

On Wednesday, August 26, 2015 at 1:27:34 PM UTC+3, Johannes Bauer wrote:
> The point would be to have better language constructs perform the same
> task in a more maintainable/readable/object-oriented fashion while STILL
> being as fast as C.
 
In my experience C++ achieves that beautifully. Classes generally do not incur any performance penalty over equivalent C code. (In fact, even virtual functions do not usually incur any measurable penalty. Not that you would need to use virtual functions very often anyway.)
 
Many things are actually more efficient in C++ than in C, due to the nature of C++. For example std::sort() is faster than qsort(), and one major reason for that is that the compiler can perform more optimizations based on the element type being sorted.
jacobnavia <jacob@jacob.remcomp.fr>: Aug 26 01:05PM +0200

Le 25/08/2015 01:14, jacobnavia a écrit :
> open source (no license) available at:
 
> https://code.google.com/p/ccl/
 
> Have fun!
 
Interesting that none of the C++ heads objects to this :-)
jacobnavia <jacob@jacob.remcomp.fr>: Aug 26 02:11PM +0200

Le 26/08/2015 12:27, Juha Nieminen a écrit :
> If you have something like "struct A { Container cont; };" you now have to
> make sure that every time you instantiate that struct, you construct and
> destroy its member appropriately (and of course manually.)
 
No. My C compiler system features garbage collection. Using Boehm's
software, you do not need to do anything "manually".
 
Just forget about reclaiming memory and the CCL wil work almost as C++
does. You do not need to reclaim anything. It will be reclamied
automatically.
jacobnavia <jacob@jacob.remcomp.fr>: Aug 26 02:13PM +0200

Le 26/08/2015 12:27, Juha Nieminen a écrit :
>>> And debugging macro-based dynamic data containers must be a joy.
 
>> >It is. The source code is available and easy to debug.
> You don't even understand what I'm saying, do you?
 
You didn't even answer to the concrete example I showed:
 
Here is it again:
For instance here is an example of the C macros used:
 
102 static int Sort(VECTOR_TYPE *AL)
103 {
104 CompareInfo ci;
105
106 if (AL == NULL) {
107 return NullPtrError("Sort");
108 }
109 ci.ContainerLeft = AL;
110 ci.ExtraArgs = NULL;
111 qsortEx(AL->contents, AL->count, AL->ElementSize,
AL->CompareFn, &ci);
112 return 1;
113 }
 
The only generic argument is the type name of the elements stored in the
vector: "VECTOR_TYPE".
 
Is this too much for you?
 
 
Can you tell me what is here so difficult to debug????
 
> We have a serious case of dogma here, it seems.
 
Where is the dogma?
David Brown <david.brown@hesbynett.no>: Aug 26 02:22PM +0200

On 26/08/15 14:11, jacobnavia wrote:
 
> Just forget about reclaiming memory and the CCL wil work almost as C++
> does. You do not need to reclaim anything. It will be reclamied
> automatically.
 
So you are saying that the CCL can do a similar job to the C++ container
library, and avoids error-prone C-style memory management, but only if
you are using your particular non-standard C compiler? And for normal C
compilers, the CCL works but all memory management must be handled
manually (in the way other posters here have described) ?
 
That's okay, of course - you are free to make your own "extended C"
compiler and libraries, and recommend their usage. But when discussing
C and how it compares to C++, you need to either stick to standard C, or
at least make it clear when you rely on features from a particular
non-standard compiler.
 
(The same would apply if someone were to suggest the gcc "cleanup"
attribute as a way of managing automatic resource cleanup.)
BGB <cr88192@hotmail.com>: Aug 26 07:51AM -0500

On 8/26/2015 3:11 AM, Juha Nieminen wrote:
>> Foo_Whatever(obj, ...);
 
> The point is that a "generic" data container in C can't make that kind of
> call (because there's no function overloading in C.)
 
possible, unless one gets extra nasty with a lot of macros.
but, yeah, using function-pointers and plugging things together to make
logic often gets reasonably passable performance.
 
 
as-noted, I don't really use any "generic containers" personally, mostly
throwing together code specific to the task as-needed.
jacobnavia <jacob@jacob.remcomp.fr>: Aug 26 03:28PM +0200

Le 26/08/2015 14:22, David Brown a écrit :
> So you are saying that the CCL can do a similar job to the C++ container
> library, and avoids error-prone C-style memory management, but only if
> you are using your particular non-standard C compiler?
 
No, I am not saying that. Since that is not true.
 
Boehm's GC works with all compilers around, gcc, MSVC, llvm, WHATEVER.
 
Besides, my compiler is not "not standard". It follows the C99 standard.
David Brown <david.brown@hesbynett.no>: Aug 26 04:04PM +0200

On 26/08/15 15:28, jacobnavia wrote:
>> you are using your particular non-standard C compiler?
 
> No, I am not saying that. Since that is not true.
 
> Boehm's GC works with all compilers around, gcc, MSVC, llvm, WHATEVER.
 
Fair enough - but it would be very useful to explain that, since it is
(apparently) critical to the practical use of CCL, and the great
majority of C programming is done without a garbage collector.
 
> Besides, my compiler is not "not standard". It follows the C99 standard.
 
I was under the impression that the garbage collector was an extension
that your compiler included (since you wrote "My C compiler system
features garbage collection"), and since I know it provides a number of
other extensions.
 
But my wording was bad - if your compiler supports C99 standards (at
least to a reasonable level), then it is indeed "standard" even though
it also has extensions. I merely meant that if the CCL works best with
a compiler with extensions that are not part of standard C, then you
should say so here.
"Öö Tiib" <ootiib@hot.ee>: Aug 26 10:40AM -0700

On Wednesday, 26 August 2015 11:13:29 UTC+3, Wouter van Ooijen wrote:
 
> That extern C function can easily call a C++ function (by name when it
> is declared extern "C", or by passing it a function pointer), which can
> raise an exception.
 
We can use C++ fully within code of function defined extern "C".
My point was about letting exceptions to fly out from such
function. That is wrong since C++ exceptions are not C interface.
Function pointers of usual C++ and extern "C" functions are not
compatible. It is common extension that these are compatible
but C++ does not guarantee it.
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: