From: jp2code on
I want a loop to run in my RUNTIME_CLASS object derived from CWinThread.

I can initialize my thread, and I can call portions of my class.

But, how do I specify that I want to run a Loop after everything has
initialized?

I was planning on placing this loop inside the overridden Run method, but
the Help says this is rarely done.

Should I place my loop somewhere else? That's fine by me, but then how do I
call it?

If I use PostThreadMessage and having my message handler call the loop
function, then the message handler will not return (or process any other
messages) until the loop has completed - which will only happen after the
thread is complete.


From: Joseph M. Newcomer on
Wrong approach. If you are running a continuous loop, you don't want a UI thread. If you
are running a UI thread, you don't want a continuous loop. The two models are
incompatible.

Here's a really good heuristic: if you think you need to modify the Run method, you are
wrong. If you think real hard about why you need to do it and decide it is the right way,
you're still wrong. 99.999% of the time this heuristic give you a correct answer.

I think you do not understand threading, asynchronous I/O, or serial I/O well enough to
see the architecture. Take a look at my essay on serial port I/O. It is a subset of
several solutions I have implemented, but it is closer to an approach than what you have
proposed. Note that it uses "pseudo-synchronous" I/O to handle both sides of the
communication, but it is essential that you use asynchronous I/O and have separate threads
for input and output.

You should not have a loop at all. The fact that you think you need a loop of the nature
you describe suggest that you really need to understand threading and asynchronous I/O
more deeply.

Take a look at my essays on UI threads, worker threas, the use of I/O completion ports,
and my serial I/O essay; once you have studied those, you may see the correct answer to
your question more clearly.
joe
On Tue, 5 Jun 2007 11:33:11 -0500, "jp2code" <poojo.com/mail> wrote:

>I want a loop to run in my RUNTIME_CLASS object derived from CWinThread.
>
>I can initialize my thread, and I can call portions of my class.
>
>But, how do I specify that I want to run a Loop after everything has
>initialized?
>
>I was planning on placing this loop inside the overridden Run method, but
>the Help says this is rarely done.
>
>Should I place my loop somewhere else? That's fine by me, but then how do I
>call it?
>
>If I use PostThreadMessage and having my message handler call the loop
>function, then the message handler will not return (or process any other
>messages) until the loop has completed - which will only happen after the
>thread is complete.
>
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: jp2code on
I'm reading your essay on worker threads, but I won't be able to impliment
asynchronous I/O because we include WinCE / PocketPC devices, and they do
not support overlapped operations.

Currently, I have a main thread for writing, a worker thread for reading,
and a global BOOL value called (ironically) g_Overlapped.

Here is how I use it:

Main Thread - Writing:
while (g_Overlapped)
Sleep(1);
g_Overlapped = TRUE;
g_Overlapped = WriteFile( ... );
if (g_Overlapped)
{
g_Overlapped = FALSE;
// code to process
}

Worker Thread - Reading:
while (g_Overlapped)
Sleep(1);
g_Overlapped = TRUE;
g_Overlapped = ReadFile( ... );
if (g_Overlapped)
{
g_Overlapped = FALSE;
// code to process
}

This should work, wouldn't you think?


From: Scott McPhillips [MVP] on
jp2code wrote:

> I'm reading your essay on worker threads, but I won't be able to impliment
> asynchronous I/O because we include WinCE / PocketPC devices, and they do
> not support overlapped operations.
>
> Currently, I have a main thread for writing, a worker thread for reading,
> and a global BOOL value called (ironically) g_Overlapped.
>
> Here is how I use it:
>
> Main Thread - Writing:
> while (g_Overlapped)
> Sleep(1);
> g_Overlapped = TRUE;
> g_Overlapped = WriteFile( ... );
> if (g_Overlapped)
> {
> g_Overlapped = FALSE;
> // code to process
> }
>
> Worker Thread - Reading:
> while (g_Overlapped)
> Sleep(1);
> g_Overlapped = TRUE;
> g_Overlapped = ReadFile( ... );
> if (g_Overlapped)
> {
> g_Overlapped = FALSE;
> // code to process
> }
>
> This should work, wouldn't you think?

No. You don't understand the race conditions that are inherent in
multithreading. You cannot test the flag and then assume that it is
unchanged in the next instruction. Synchronization primitives are
necessary: You can't do it with if, while, etc.

You need to stop coding and work on the design. (Or find some
experienced help.)

--
Scott McPhillips [MVP VC++]

From: Joseph M. Newcomer on
See below...
On Tue, 5 Jun 2007 14:10:53 -0500, "jp2code" <poojo.com/mail> wrote:

>I'm reading your essay on worker threads, but I won't be able to impliment
>asynchronous I/O because we include WinCE / PocketPC devices, and they do
>not support overlapped operations.
>
>Currently, I have a main thread for writing, a worker thread for reading,
>and a global BOOL value called (ironically) g_Overlapped.
>
>Here is how I use it:
>
>Main Thread - Writing:
> while (g_Overlapped)
> Sleep(1);
****
This is REALLY BAD.
WaitForSingleObject(g_Overlapped);
might make sense, but one thing that is a near-certainty: if you have to put a Sleep()
call in a thread to make it work, the design is wrong. After reading this a second time,
I am convinced that this is an incorrect attempt to provide mutual exclusion. Consider
what happens if g_Overlapped is set FALSE. The upper thread drops down and tries to set
g_Overlapped to TRUE. But right before the store instruction that moves TRUE to
g_Overlapped,the scheduler says "end of your timeslice". It then dispatches the lower
thread. The lower thread was about to do the load of g_Overlapped when it was suspended.
So it loads FALSE, discovers that it, too, can do a Write, and now both threads are trying
to access the serial port at the same time.

Nothing but a total rewrite can save this code. It is a time bomb waiting to happen, and
eventually it WILL blow up. That is guaranteed beyond any shadow of doubt. It is not a
question of 'if' but merely 'when'. The probability that it will fail some time in the
future is exactly 100%.
*****
> g_Overlapped = TRUE;
****
So why is it being set above and then reassigned below? [Never mind, I see in the second
reading that this is just flat-out wrong programming and will have to be rewritten]
****
> g_Overlapped = WriteFile( ... );
> if (g_Overlapped)
> {
> g_Overlapped = FALSE;
****
Every use of g_Overlapped is erroneous code.
****
> // code to process
> }
>
>Worker Thread - Reading:
> while (g_Overlapped)
> Sleep(1);
****
This is even more confusing. Why are two threads testing the same variable and taking
actions that set and reset it? This looks frighteningly like some bizarre attempt to get
mutual exclusion without using any mutual exclusion primitive, which is beyond any shadow
of doubt a total flaming disaster and absolutely MUST be redone!

[pass 2] it IS a total flaming disaster.
****
> g_Overlapped = TRUE;
> g_Overlapped = ReadFile( ... );
> if (g_Overlapped)
> {
> g_Overlapped = FALSE;
> // code to process
> }
>
>This should work, wouldn't you think?
****
Actually, I would be amazed if it could possibly work. Secondly, if it does work, it is
horrendously inefficient. I don't even know if CE *can* sleep for 1ms (as opposed to 10
or 15 or some other value) but in any case, polling is not synchronization, and polling
non-synchronized variables is simply flat-out completely wrong and any illusion that it
works is miraculous.

If you want mutual exclusion, you MUST use a mutex or CRITICAL_SECTION. There are zero
other choices.
joe
>
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm