"delete this" question

  • Thread starter Christopher Benson-Manica
  • Start date
P

Phlip

Christopher said:
Well, neither I nor my coworkers much care, but presumably there are
places and bosses where that is the standard, so it's worth at least
being thus forewarned...

Ookay. Read /Design Patterns/. It sounds like your colleagues are not even
at this level yet...
Well, I guess I should have chosen my words more carefully - the file
has the contents of a list of data structures, each of which needs to
be parsed before the program can begin its real work.

Are you trying to read blocks in one thread and parse in another? If so,
there's no point. The hard drive controller reads file tracks while the disk
is spinning, so their data blocks are ready each time you call ReadFile().
So you already have blocks reading in one thread and parsing in another.

We are nearing the concept "Premature optimization" here...
 
C

Christopher Benson-Manica

Phlip said:
Ookay. Read /Design Patterns/. It sounds like your colleagues are not even
at this level yet...

Well, on the bright side, it's sitting within easy reach on this desk.
Unfortunately there's very little designing or redesigning going on
relative to the amount of maintaining...
Are you trying to read blocks in one thread and parse in another? If so,
there's no point. The hard drive controller reads file tracks while the disk
is spinning, so their data blocks are ready each time you call ReadFile().
So you already have blocks reading in one thread and parsing in another.

No, I'm reading and parsing in one thread while the rest of the
initialization continues courtesy of the service control manager.
 
A

Alf P. Steinbach

* Phlip:
* Christopher Benson-Manica:


I disagree.

...
there are no urprises.

Sorry, the analysis is flawed.

A B-object may be terminated unexpectedly when it is used in place of
an A, under A assumptions.

For example, the code holding a presumed A (really a B) may be unaware
that some other, event-driven code holds a pointer to the B object as
a B, and terminates it...

Without analysing your analysis in detail I think the flaw is perhaps an
assumption that _all_ code must be either "B-aware" or not.

That's not the case.

Bleah. He's just nitpicking. You did not turn off B's copy constructor.

It's an important nitpick.

If a B-object is inadvertently copied, the result is undefined.

That means a possible later catastrophic error that nobody understand
at all.


And B does not "require" dynamic allocation, because you could create B on
the stack and then decline to call go().

Well, the Titanic was a safe ship, because you could refrain from bording.

Nitpicking again. You wrote 'cout' inside a class that should not surprise
clients with a side-effect that the user can see. Big friggin' deal.

Affects reusability and not the least, complicates the code (in general).
 
J

Joe Seigh

Phlip said:
Now let's upgrade this design, to decouple it and make it event driven:

click the button
change the button label to "cancel scan"
post a WM_TIMER message

on WM_TIMER message
fetch the next file name
if there's a next file
is it infected?
post a WM_TIMER message

The part "fetch the next file name" now uses a linked list of opened folders
to pull out the next one. This strategy decouples the act of traversing the
folder hierarchy from the act of inspecting for virii. Decoupling is good.
This strategy uses no threads, and uses a windows timer to cleanly start and
stop the scan. (Stop the scan by cancelling the current WM_TIMER message.)

The strategy is "event driven" because it doesn't store state in the current
location of control flow. The recursive function stores the current folder
state locally, on the stack, and coupled to the file scanner. The event
driven system stores the current folder state explicitely in a linked list.
This, in turn, makes the folder traversal system modular and reusable.

How would you handle multiple different asynchronous actions with WM_TIMER
messages which may or may not be invoked concurrently? You'd have to multiplex
them somehow and guarantee fairness in execution.
 
K

Kristo

Christopher said:
Is the following code legal, moral, and advisable?

#include <iostream>

class A {
private:
int a;

public:
A() : a(42) {}
~A() {
std::cout << "A's destructor called, a is " << a << std::endl;
}
};

class B : public A {
private:
int b;

public:
B() : b(666) {}
~B() {
std::cout << "B's destructor called, b is " << b << std::endl;
}
void go() { delete this; }
};

int main() {
B *b=new B();
b->go();
return 0;
}

Yes, but you must be *very* careful. See the FAQ for details.

Kristo
 
L

Larry I Smith

Christopher said:
(Moving to comp.programming.threads - if you don't read that group,
come back to clc++...)


Well, my specific intention for this thread is for it to take care of
caching the contents of a file in memory as my program is starting.
The main thread can't wait that long, because the program is a Windows
service and the service manager isn't willing to wait forever for my
program to start. I know I could do this other ways, but is there
really a big disadvantage to spawning a thread to handle the caching
of this file?

No, not "a big disadvantage".

Threads used correctly (it takes some practice) can enable
quite complex & responsive applications. The "threads good
or bad" discussion depends on many complex factors; like all
tools, they have their uses, but they (nor anything else) are
not a "silver bullet".

Larry
 
P

Phlip

Joe said:
How would you handle multiple different asynchronous actions with WM_TIMER
messages which may or may not be invoked concurrently? You'd have to multiplex
them somehow and guarantee fairness in execution.

Besides WM_TIMER comes with a payload integer to distinguish message
streams?

At some point you give up and add a thread. You use it as carefully and
judiciously as possible. Don't use threads like a baby who has just learned
to use a hammer, and thinks everything looks like a nail.

(Note I'm busting on languages that make threads "easy"...)
 
J

Joe Seigh

Phlip said:
Joe Seigh wrote:




Besides WM_TIMER comes with a payload integer to distinguish message
streams?

At some point you give up and add a thread. You use it as carefully and
judiciously as possible. Don't use threads like a baby who has just learned
to use a hammer, and thinks everything looks like a nail.

(Note I'm busting on languages that make threads "easy"...)

Well, it's a nice trick I suppose if you don't have threads. Otherwise it seems
a bit contrived and makes things more complicated than they need to be. One of
the reasons for threading is modularization as much as for asynchronicity or
concurrency. It's to make things simpler. I think the main culprit is not so well
thought out OO design and design patterns which cause more problems than they
solve. The "anti-patterns" if you will. I haven't messed with GUI programming
lately but the early MVC implementations in Java were atrocious and a major pain
to work with. Probably if you had the GUI primatives designed by people who
understood threading a little better and knew the thread design patterns useful
for keeping out of trouble, not so many people would find multi-threaded GUI
programming quite so traumatic. And c.p.t. wouldn't have so many posts requesting
information on deadlock detection (invariably by people doing OO GUI programming).
 
P

Phlip

Christopher said:
Well, my specific intention for this thread is for it to take care of
caching the contents of a file in memory as my program is starting.
The main thread can't wait that long, because the program is a Windows
service and the service manager isn't willing to wait forever for my
program to start. I know I could do this other ways, but is there
really a big disadvantage to spawning a thread to handle the caching
of this file?

Flirting with Deceased Equine Flaggelation Mode, but...

In your case you are a service, not a simple app, so your program already
solves concurrency issues, so one more shouldn't hurt.

But note that Win32 services uses the GetMessage() DispatchMessage() event
loop, so my multiplexing solution would still work.

Another principle here is to push as much work, creativity, and risk down to
the OS as possible. ReadFileEx().

Joe said:
Well, it's a nice trick I suppose if you don't have threads.

Per the other posts: An event driven architecture is good whether or not you
thread, and threading should not be used to avoid supplying the good
architecture.
Otherwise it seems
a bit contrived and makes things more complicated than they need to be. One of
the reasons for threading is modularization as much as for asynchronicity or
concurrency. It's to make things simpler.

And threads can break encapsulation, and force an object in one thread to
become aware of the private details and activities of an object in another
thread, waiting for it to release a semaphore.

(Before the denizens of cpt think I'm some kind of anti-threading zealot
newbie, I grew up developing for AmigaOS, which works like a modern embedded
system. Threads are necessary, and one false move with threads would send
the CPU into FIREWORKS_DISPLAY mode.)
I think the main culprit is not so well
thought out OO design and design patterns which cause more problems than they
solve. The "anti-patterns" if you will. I haven't messed with GUI programming
lately but the early MVC implementations in Java were atrocious and a major pain
to work with. Probably if you had the GUI primatives designed by people who
understood threading a little better and knew the thread design patterns useful
for keeping out of trouble, not so many people would find multi-threaded GUI
programming quite so traumatic.

Are you implying that there are GUI architectures that thread each input
event as the _default_??
And c.p.t. wouldn't have so many posts requesting
information on deadlock detection (invariably by people doing OO
GUI programming).

I rest my case.
 
T

Torsten Mueller

Phlip said:
click the button
open a folder
open a sub folder
read a file
is it infected?

click the button
change the button label to "cancel scan"
post a WM_TIMER message

on WM_TIMER message
fetch the next file name
if there's a next file
is it infected?
post a WM_TIMER message

The part "fetch the next file name" now uses a linked list of opened
folders to pull out the next one. This strategy decouples the act of
traversing the folder hierarchy from the act of inspecting for
virii. Decoupling is good. This strategy uses no threads, and uses a
windows timer to cleanly start and stop the scan. (Stop the scan by
cancelling the current WM_TIMER message.)

No, I cannot agree with this. This is not a real decoupling. The
former thread is indeed decoupled from the GUI and perhaps the GUI can
really remain active but there's still a new coupling on another
controlling instance (in this case a timer). In my opinion this timer
destroys the whole algorithm by cutting it into infinitesimal small
pieces. What if I want to execute it at once? I hate destroyed
algorithms especially if they are complicated. Good luck for debugging
this!

Some years ago I implemented an editor control supporting syntax
highlighting. After some weeks of development I found it a good idea
to use a background thread for the parsing and coloring algorithm
itself because opening a large file could take a really long time.
During this time my control did display the text in black and white,
some seconds later the color came along. Every pressed key did start
or reset a timer and after a short while the thread was executed again
to show the text in perhaps new colors. Still today I think this was a
good reason to use a thread in a GUI.

T.M.
 
P

Phlip

Torsten said:
No, I cannot agree with this. This is not a real decoupling. The
former thread is indeed decoupled from the GUI and perhaps the GUI can
really remain active but there's still a new coupling on another
controlling instance (in this case a timer). In my opinion this timer
destroys the whole algorithm by cutting it into infinitesimal small
pieces. What if I want to execute it at once? I hate destroyed
algorithms especially if they are complicated.

A major metric for decoupling is testability. The "before" pattern cannot
test the folder recursion system isolated from the file scanner. The "after"
pattern can test the WM_TIMER, the file scanner, and the folder recursion,
all three isolated from each other.
Good luck for debugging this!

Uh, I actually implemented the "after" pattern, using Test-Driven
Development, and when I was finished adding tests it had no bugs. I often
used the debugger to step thru the code and watch it work, but I never
_needed_ to use the debugger.

If changing requirements caused a bug, in the future, and if tests did not
catch it, the test cases would make an excellent platform for debugging (or
even just for trace statements) to detect the problem. Then new tests on the
problem, and the existing tests, would prevent the bug fix from creating new
bugs.

On review, the client liked the code structure and my coding style.

So, no luck will ever be required to debug my implementation of this
pattern.

Threads make bug repression a nightmare because race conditions might behave
in simple tests different from in production.
Some years ago I implemented an editor control supporting syntax
highlighting. After some weeks of development I found it a good idea
to use a background thread for the parsing and coloring algorithm
itself because opening a large file could take a really long time.

If you need to eat a sandwich in one hand and drive with the other, thread.
During this time my control did display the text in black and white,
some seconds later the color came along. Every pressed key did start
or reset a timer and after a short while the thread was executed again
to show the text in perhaps new colors. Still today I think this was a
good reason to use a thread in a GUI.

How does VS6 or VS7 highlight its syntax in realtime, without a refresh
period?
 
T

Torsten Mueller

Phlip said:
I often used the debugger to step thru the code and watch it work,
but I never _needed_ to use the debugger.

You never had to explain an application somebody else wrote, perhaps a
person using a strange programming style (this is because normally he
was a lisp programmer), speaking another native language and nobody
has seen him for years?
If changing requirements caused a bug, in the future, and if tests
did not catch it, the test cases would make an excellent platform
for debugging (or even just for trace statements) to detect the
problem. Then new tests on the problem, and the existing tests,
would prevent the bug fix from creating new bugs.

No. You cannot guarantee a software quality by tests. I always have to
fight against this opinion (especially managers do think like this).
Tests are nothing but an emergency break, something one can use too if
nothing else has left (especially if the software's design and
implementation do not guarantee it's quality).
On review, the client liked the code structure and my coding style.

And who is the client? A customer? I mean - a user?
Threads make bug repression a nightmare because race conditions
might behave in simple tests different from in production.

Normally threads are testable non-threaded! In most cases you can
write down an entire algorithm, debug it, test it, optimize it, and
then you can say, this function runs as a thread now. OK, if you have
several concurrent threads it would be more complicated.
How does VS6 or VS7 highlight its syntax in realtime, without a
refresh period?

These applications do support just a few hard coded languages. My
editor control was open to support *any* language having been defined
by semantic rules in an initialization file. And I supported nested
comments (this takes a lot of time more than just C/C++ comments). If
you take a look upon Visual Assist (coloring function names, class
names, matching brackets ... in Visual Studio) you will see threading
is surely needed for background parsing and coloring of a text.

T.M.
 
P

Phlip

Torsten said:
You never had to explain an application somebody else wrote, perhaps a
person using a strange programming style (this is because normally he
was a lisp programmer), speaking another native language and nobody
has seen him for years?

That's out of context. I described a project I wrote from scratch.

If someone gives you a program built by Debugger-Driven Development, you
have no choice but to pick up where they left off.
No. You cannot guarantee a software quality by tests.

Of course not. But you sure as hell can avoid long bug hunts.
I always have to
fight against this opinion (especially managers do think like this).
Tests are nothing but an emergency break, something one can use too if
nothing else has left (especially if the software's design and
implementation do not guarantee it's quality).

So why not write tests before writing the tested code? That makes them
efficient to write, turning them from a backup situation into a way to
propel development.
And who is the client? A customer? I mean - a user?

A programmer who must maintain that code.
Normally threads are testable non-threaded! In most cases you can
write down an entire algorithm, debug it, test it, optimize it, and
then you can say, this function runs as a thread now. OK, if you have
several concurrent threads it would be more complicated.

Things which are hard to test should be avoided. That's a sign they bring
too much complexity.

If they are, in fact, the simplest spot between even more complexity, tests
can detect this situation, and can reinforce the fixes.
 

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

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,178
Latest member
Crypto Tax Software
Top