Amiga.org
Operating System Specific Discussions => Amiga OS => Amiga OS -- Development => Topic started by: Karlos on December 12, 2002, 10:45:11 AM
-
Hi all,
I've been writing some system classes in StormC/C++ v3. I have written a threadable class (similar to Thread in java) that encapsulates a dos Process. Everything is fine apart from exception handling. Whenever any given thread method throws an exception, it seems that the actual task that threw it isn't always the one to catch it.
For example, the protected GoIdle() method only ever throws an IllegalAccess if not called by the internal task. Other methods eg Wake() thow exceptions if they are called by the internal task.
So imagine our thread is sleeping via GoIdle(). The only exception it is expecting is IlegalAccess, which shouldn't happen anyway because it has been called by the internal task. Everything is fine so far. Now imagine the parent task calls some method such as Start() that will throw AlreadyRunning. The internal thread ends up catching this!!
Have actually managed to prove this by catching AlreadyRunning from the following fragment
/* this code executed by internal task */
try {
GoIdle();
}
catch (AlreadyRunnging) {
// not even thrown by GoIdle()!!
cerr << "Bloody Hell!\n";
}
catch (IllegalAccess) { /* Nowt to do */ }
Basically the whole thing then crashes as the wrong stack is unwound!
I'm aiming for portability and really want to use execptions for error handling rather than having to use return values etc. Any help welcome!!!
-
Well a simple test I did with GCC last night worked
fine.
When you throw an exception a stack unwind occurs
rapidly.
The problem might be the way StormC handles the
stack unwind when two tasks are present in the same context. If I recall correctly task creation
requires part of the stack passed as a pointer but
I need to go look at docs.
My current working theory is that StormC does not
differentiate between tasks during a stack unwind.
This is Blade's area and I haven't seen
him on here for a bit since he was sent death threats.
Anyway... still working on this but I thought I would
make sure you knew I was still looking.
Have you tried this without using the dos process implementation - say use an exec task instead? That would be much easier to debug.
-
Thanks!
Can't hang about today, so I'll probably be offline when you read this...
I also think that the problem lies in StormC implementation. I have catalogued some serious problems with StormC v3 over the time I have been using it. For example, my major gripes are
1. Broken function template instansation, eg
int MyFunc(X a, Y b)
{
//....
}
int main()
{
int x = MyFunc(2, 1.7);
return x;
}
will crash the compiler :-o
2. Allocation of arrays of polymorphic objects using new [] sometimes fails to call the default constructor for all but the first element. Jeez! Had to write a global template New() function ( and corresponding Delete()) ) for this that uses placement operator new to construct each member correctly. Later discovered that an expression such as
MYPOLYCLASS *p = new MYPOLYCLASS[16]();
works in all cases I tested. However, other compilers (eg Watcom under Windoze) gripe about the above syntax. After all there are parameterized versions of new[] ().
3. You can take the address of a non-static member function of a class without an object. Dangerous! Doesn't even give a warning :roll:
4. Lots more small deviations from the recommended standard.
Back to the point, coI'm really not surprised if the exception handling mechanism is botched. My THREAD class encapsulates a dos Process such that it is IO capable. Haven't tried using a basic exec Task instead. I'll give it a go later.
Anyway, I'm quite tempted to move to GCC, but have to confess I'm spoiled after using Storms IDE.
Well, thanks again for the advice and good hunting :-)
-
Well I have long since given StormC 3 up as a pile of
turd WRT its C++ support. I think v4 is based on GCC ;-)
I know what you mean about IDEs but I prefer HiSoft C++'s IDE
which shares the same compiler code origins with StormC3
AFAIR.
Anyway reproduced your problem with StormC exceptions
last night with both Dos processes and exec tasks.
When you run it through the debugger you can reproduce it
every time if the exception is thrown immediately prior to
a context swap to the child task.
So what I did was play around with the priority of the
subtask to reduce the probability that Exec would decide
to swap to the child.
Then the exception was caught in the parent... sometimes!
I actually prefer to do my development using Visual SlickEdit on
my Mandrake 9 box
exporting its display to AmiWinX and using an NFS mounted
shared filesytem to store the files. I then use Visual SlickEdit
macros to drive the GCC compiler on the Amiga by use of
rsh.
I am not a GoldEd fan but apparently that is quite good too.
I havent yet tried your other bugs out but rest assured that
erratic template support was my biggest gripe with StormC3 and HiSoftC++
but also more importantly in MSVC5!
-
I'm quite tempted to get StormC v4. I'm way to broke at present though.
I guess I should install gcc (again). I never seem to get it set up correctly though!
I contacted Haage & Partner about many of the V3 problems I encountered and they agreed that V3 had many problems which was part of the reason they switched to GCC.
Their advice?
Get V4 :-)
-
What C++ compilers do we have?
Maxxon C++
Hisoft C++
StormC v3, v4
GCC
Anyone know of any more?
-
What about EGCS? I haven't actually tried it, I recall that it has C++ support but may be wrong.
Is anybody else reading this thread, or is it just me and thee, Dave?
-
No, I'm reading it too, but C++ is not my cup of tea, although I am interested in anything doing with threading. To answer your question: egcs used to be a separate branch from the main gcc-tree, but ever since the FSF saw the light and realised that the egcs-committee was doing a better job of improving and maintaining the compiler than they themselves ever could, egcs 'became' gcc. egcs is obsolete; it's all gcc now.
-
@Cymric
Thanks for clearing that for up me - egcs was some hazy distant memory in the back of my head :-)
-
@Karlos
Unless I find anything useful to you in the next day or so
this is probably going to be my last comment on this.
C++ exception handling is one of the worst culprits for semantic
problems during porting between operating systems.
Although I like what exceptions do as far as code clarity
is concerned a couple of years ago I took the decision
to return to passing back return codes from methods.
Since then I have experienced only the usual suspects in
getting my applications ported between platforms ( endianness,
codepages etc ).
The other problem that comes out ( aside from compiler template
support I guess ) is multiple inheritance. This seems to be implemented
erratically in compilers.
So I have returned to non virtual single inheritance and where a
seperate inheritance relationship is required make the superclass
pure virtual with no implemented constructor/destructor forcing
the subclass implementor to treat it like an "Interface" only.
Oh and always write your own smart pointer or use someone
elses. Saves a lot of work later on!
-
Thanks Dave,
I must say that I do pretty much follow the same design paradigms as yourself. I do use multiple inheritance occasionally, but am always careful of using such things lightly.
I've used return values since my C coding days, the switch to move to exceptions was purely experimental. Given the problems it has caused me in multithreaded code I have switched back to the return value technique.
Well, thanks for your time and I'll probably catch you in another exceptional thread later (all puns intended) :-)
-
Have you found a good way of handling loading modules
by ordinal name with the Amiga yet?
I have never been able to get a convincing DLL or Shared Object
style mechanism working...
-
I can't say I have as of yet. It is something I intend to look at later - I want to have loadable class implementations to keep application executable sizes down.
The nearest thing I managed so far was to write the implementation of a class as a standard .library (apart from inines etc) file and hide the library handling code away in the private section of the class. Not the most technically excellent approach but it worked after a fashion. You still needed to have a small link library.
-
Oh and always write your own smart pointer or use someone
Umm... what's a smart pointer?!?
- Mike
-
Maintains a reference count to an object and when
the reference count hits zero the object is deleted.
I can post a code example of a really good smart pointer / auto pointer if you'd like to see how it is done.
-
Why would you need to know the reference count? I would assume only when more then one thread references the same instance? Sure, if you have the code handy I wouldn't mind taking a look through it. Thanks.
- Mike
-
Not really. \When you pass an object by reference
the reference count increases to include the scope
of the other object, and when you return from the by reference call it decreases.
More than one object might hold a reference to the
same object instance, e.g.
BankAccount class instance 012454 might reference Person class instance DaveP and so might BankAccount class instance 012455 ( I own both those accounts ).
Thus if someone deletes BankAccount 012454 only the reference count to DaveP is decremented. If they delete the 012455 then the reference count is zero and DaveP gets dropped from memory. That is of course if it is not held by another container class that looks after Person instances.
In fact when you start looking at the difference between active ( in memory ) instances vs passivated ( in storage and no longer in memory ) it gives you a neat lead.
Further to this if there are multiple places where the object could need to be removed and it is run time conditional.
say you are in a complex nesting of try/catch blocks and the object instance is allocated somewhere in the mid point.
You could follow the laborious principle that each level of nesting that makes an allocation that the parent nesting is aware of should catch every exception de-allocate and rethrow. However that leads to ridiculously inpenetrable code.
Better to rely on the stack unwind principle. Thus a smart pointer allocated in the mid point would automatically deallocate the memory ( if it is not used elsewhere - an important point when you start getting into using container classes ) during unwind and therefore you do not need to catch rethrow just for deallocation or somehow "inform the parent" of the allocation or WORSE leak because you weren't aware of what will happen during an exception throw.
When might this be important? Well say the midpoint in the try catch not only creates a new bank account but adds it to the container for all bank accounts. This means the reference count is now two. If the bank account is passed to a child scope then the reference count is now three. IF an exception is thrown the reference count is now one and the object does not get deleted. Fine if you want to up front determine what the code is doing you could probably set some flag to indicate that the bank account memory is now owned not by the original scope of the allocator - but that is the point. In complex situations ( which occur 8 times out of 10 ) you start setting flags in order to give a catch block or some other code some indication of how to handle allocations and de-allocations depending on the flow of logic.
Better, more elegant and even easier for the human mind to manage ( and for subsequent program maintainers such as change teams ) if the decision to use auto/smart pointers and reference counting up front.
Note that to implement a good auto pointer ( not the one found by default in later revisions of C++ ) you are best putting the reference counting in some parent "Object" class AND the auto pointer has to be passed "by value" everywhere to force the copy constructor to do its work.
-
DaveP wrote:
What C++ compilers do we have?
Maxxon C++
Hisoft C++
StormC v3, v4
GCC
Anyone know of any more?
i once heard something of a C/C++ compiler named ColdFire. i don't know about it's current status, though.
-
Glaucus wrote:
Why would you need to know the reference count? I would assume only when more then one thread references the same instance? Sure, if you have the code handy I wouldn't mind taking a look through it. Thanks.
- Mike
Smart pointers hare handy for all kinds of things. I wrote one as part of a cacheing implementation for managing volatile data loaded from disk in a preallocated block of memory. When the reference count hits zero, the space used by the object was up for recycling.
I also used a variant of this smart pointer that was able to write back data modifications to files once the reference count was zero (prior to releasing the memory). All interesting stuff.
-
What C++ compilers do we have?
Maxxon C++
Hisoft C++
StormC v3, v4
GCC
Anyone know of any more?
How could you forget VBCC (http://sun.hasenbraten.de/vbcc/)?
Bloody Heretic! ;)
-
When I posted a link to this thread, I wasn't expecting it to be resurrected...
How could you forget VBCC (http://sun.hasenbraten.de/vbcc/)?
Bloody Heretic! ;)
VBCC, though an excellent C compiler for Amiga, does not compile C++. It supports a subset of the C99 specification, however.
-
When I posted a link to this thread, I wasn't expecting it to be resurrected...
VBCC, though an excellent C compiler for Amiga, does not compile C++. It supports a subset of the C99 specification, however.
Well that's me looking like a right tit then! :lol:
-
@nicholas
Since you resurrected the thread, I might as well point out that the original issue went away (with several others) after migrating the code to StormC4's gcc implementation and linking with threadsafe.lib
No point in soliciting replies to a problem that was fixed 6 years ago :lol:
Well that's me looking like a right tit then!
Look before you leap!
So, since we've broadened it to C, what else (other than VBCC) do we have?
GCC, Aztec, Lattice, Maxxon, DICE...
-
Have you found a good way of handling loading modules
by ordinal name with the Amiga yet?
I have never been able to get a convincing DLL or Shared Object
style mechanism working...
Seven years later and it's a feature of the OS... coincidence? :lol:
-
@nicholas
Since you resurrected the thread, I might as well point out that the original issue went away (with several others) after migrating the code to StormC4's gcc implementation and linking with threadsafe.lib
No point in soliciting replies to a problem that was fixed 6 years ago :lol:
Look before you leap!
So, since we've broadened it to C, what else (other than VBCC) do we have?
GCC, Aztec, Lattice, Maxxon, DICE...
SAS (I just found my ADFs of this recently, after considering whether or not to dispose of the manuals)
-
SAS (I just found my ADFs of this recently, after considering whether or not to dispose of the manuals)
Wow, SAS-C. How'd I manage to miss that?