mfc >> Thread Proc Parameter

by MarcS » Thu, 23 Mar 2006 06:14:55 GMT

Lets say we have a function that is started in another thread:

UINT ProcessData(LPVOID lpParam)
{
MyClass* pMyClass = (MyClass*)lpParam;
...
pMyClass = NULL;
return 0;
}


MyClass is NOT an MFC class and is NOT derrived from any other class.

1.) I have read that MFC classes should be passed to thread procs by
m_hWnd but I have read nothing of generic classes. Is this safe? If not
what is the alternative? Global variables (yuck)?

2.) I know that we want to set pMyClass to NULL before the function
returns (or TerminateThread is called in a last-case situation) but
what about lpParam? I am assuming that when the function exits that it
is automatically cleaned up but what if we have to use TerminateThread
because a function like FtpWriteFile() is blocking for some reason?

Also, if the function does block, I am doing the following:


{
CWinThread* pThread =
AfxBeginThread((AFX_THREADPROC)ProcessData,pMyClass, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
pThread->m_bAutoDelete = FALSE;
pThread->ResumeThread();

if (WaitForSingleObject(pThread->m_hThread,20000) == WAIT_TIMEOUT)
{
// Function blocks so we must force the thread to terminate.
CloseHandle(pThread->m_hThread);
TerminateThread(pThread->m_hThread,0);
}
delete pThread;
}

Is this the safest "last-resort" method for killing a blocked thread?

Thanks a bunch,
Marc S



mfc >> Thread Proc Parameter

by Scott McPhillips [MVP] » Thu, 23 Mar 2006 08:02:17 GMT






Passing a non-CWnd pointer here is safe.



Huh? There is no reason to NULL pMyClass and it has no effect.
Whatever you think it accomplishes is a misunderstanding. If you were
to use TerminateThread there is no way to avoid memory leaks.



If your code needs the cast on ProcessData you have deeper problems.

It is invalid to use a handle after you have closed it. Reverse those
two statements, though, and you've done all you can do as a last resort.
If your thread is subject to blocking look into alternative ways to do
what it does. TerminateThread should never be required.

--
Scott McPhillips [VC++ MVP]




mfc >> Thread Proc Parameter

by Josh McFarlane » Thu, 23 Mar 2006 08:10:36 GMT




Depends. You don't want to be touching windows at all in the thread.
However, other MFC classes I've never had a problem with (I throw
CString pointers to and fro between threads like nothing else.).

You've only got to keep in mind 1 thing: A. Never ever send a message
to the main thread from your new thread. B. Do not touch the GUI in the
secondary thread.

As long as you deal with sychronization issues, you should have no
problem passing variables through the parameter.


Technically, you don't NEED to set either to null. When you end the
thread, the variables holding the pointers are destroyed. If you want
to free the memory, however, you need to call delete on the pointer
before returning. All you're cleaning up is just a MyClass* variable,
which happens by default anyways when the function ends.


Technically, you never want to terminate a thread, because it may be
blocked on something that requires a critical section or some other
synchronization primitive. If you terminate it, it is never released,
and if anything else attempts to access that lock, it will freeze.

OTOH, IIRC the CloseHandle call is extraneous, as when CWinThread is
deconstructed (delete pThread) it will release the handle.

HTH,
Josh McFarlane



Thread Proc Parameter

by Ed Weir (ComCast) » Thu, 23 Mar 2006 08:20:01 GMT




| Lets say we have a function that is started in another thread:
|
| UINT ProcessData(LPVOID lpParam)
| {
| MyClass* pMyClass = (MyClass*)lpParam;
| ...
| pMyClass = NULL;
| return 0;
| }
|
|
| MyClass is NOT an MFC class and is NOT derrived from any other class.
|
| 1.) I have read that MFC classes should be passed to thread procs by
| m_hWnd but I have read nothing of generic classes. Is this safe? If not
| what is the alternative? Global variables (yuck)?
|
| 2.) I know that we want to set pMyClass to NULL before the function
| returns (or TerminateThread is called in a last-case situation) but
| what about lpParam? I am assuming that when the function exits that it
| is automatically cleaned up but what if we have to use TerminateThread
| because a function like FtpWriteFile() is blocking for some reason?


As long as you pay attention to re-entrancy issues and the class is not
deleted by another thread while still in play, you should be fine. It is
not necessary to NULL the pointer before returning. Other than the fact
that you are a separate thread (and you mind the basics), ProcessData can be
treated like any other C++ standalone function.

| Also, if the function does block, I am doing the following:
|
|
| {
| CWinThread* pThread =
| AfxBeginThread((AFX_THREADPROC)ProcessData,pMyClass,
THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
| pThread->m_bAutoDelete = FALSE;
| pThread->ResumeThread();

Keep It Simple...
CWinThread* pThread = AfxBeginThread(ProcessData, (PVOID) pMyClass);
is fine.

| if (WaitForSingleObject(pThread->m_hThread,20000) == WAIT_TIMEOUT)
| {
| // Function blocks so we must force the thread to terminate.

NOT good. Design the thread so whatever it does will not 'block'. After
all, that is the whole point of making another thread, to prevent blocking
while your main thread can continue to work.

| CloseHandle(pThread->m_hThread);

Closing the handle before you terminate the thread??

| TerminateThread(pThread->m_hThread,0);
| }
| delete pThread;
| }
|
| Is this the safest "last-resort" method for killing a blocked thread?
|

NO!! Look at why the thread would be blocked, and check the design. The
thread should be allowed to terminate on its own.

| Thanks a bunch,
| Marc S
|



Thread Proc Parameter

by MarcS » Thu, 23 Mar 2006 21:02:03 GMT

Here is the thing guys, functions like FtpWriteFile and FtpReadFile
have no idea when the connection is terminated so if the connection is
terminated while reading a block of data from the ftp server via
FtpReadFile, the function just blocks (I called Mickey Soft on that one
and apparently they can do nothing about it). I have another thread
that pings the FTP server every 20 seconds to make sure that the
connection is still alive and if it isnt it kills the read thread,
cleanly disconnects everything and redials. I have to do this because
RAS for PocketPC doesn't know when it has been disconnected by a bad
connection, broken cable or whatever.

And why not send messages to the main thread from a worker thread? I
have read everywhere that this is what you are supposed to do instead
of accessing the objects inthe main thread directly.



Thread Proc Parameter

by MarcS » Thu, 23 Mar 2006 21:09:39 GMT

Oh, by the way, I have TerminateThread() and Close Handle() in the
right order in my code I just typed it wrong yesterday. At least I know
that's not my problem.

Thanks again,
Marc S



Thread Proc Parameter

by Josh McFarlane » Thu, 23 Mar 2006 23:52:54 GMT




Have you tried setting a time-out? If so, is the bug preventing the
functions from timing out on a read?


Basically, if you call SendMessage() it may in the main thread, thus,
your worker thread will block also as SendMessage does not return until
the message is handled. If you're blocked in the main thread waiting on
something (for the worker thread to finish) send message will always
block.

So, always always use PostMessage() in the worker thread. This is why
you are warned to not access MFC windows / objects because many of the
underlying calls will call SendMessage(), and as above, if that locks
you've got two threads that no longer respond.

Josh McFarlane



Thread Proc Parameter

by MarcS » Fri, 24 Mar 2006 02:28:48 GMT

>From what I got from Microsoft there is a bug where you can't set the
timeout for those functions and they don't recognize when the
connection they are using is dropped, not in the CE world anyway.



Thread Proc Parameter

by MarcS » Fri, 24 Mar 2006 05:21:28 GMT

Wait, what pMyClass has a member that is a pointer to a CDialog? I call
pMyClass->m_cStatusDialog->ShowProgressBar() and stuff like that. I
think I may need to set up messages for that as well...



Thread Proc Parameter

by MarcS » Fri, 24 Mar 2006 05:58:13 GMT

If the pMyClass is not a window but contains a pointer to a CDialog, is
that going to be an issue? I changed the behavior so that I post
messages to the HWND of the CDialog (m_dlgStatus) to update it but is
having it passed to the thread through pMyClass and/or using
pMyClass->m_dlgStatus->m_hWnd going to be an issue?



Thread Proc Parameter

by Josh McFarlane » Fri, 24 Mar 2006 06:11:07 GMT




Simply accessing pMyClass->m_dlgStatus->m_hWnd shouldn't cause an
issue, but you may be opening up yourself to more complications /
temptation than is needed.

When I need the handle of a window to post messages to it, I just
declare something like:

CWnd* pMainWnd

and then whenever I need to notify it or send it messages, I use:

pMainWnd->PostMessage(UWM_MESSAGE_NAME, etc, etc);

That way I'm not tempted to touch inner variables of the dialog or mess
with anything I shouldn't be on the dialog.

You should note that playing with data variables will not screw up your
worker thread (It may or may not mess up the thread running the window,
but that's another discussion entirely). However, calling MFC functions
within the window based class may or may not lock your thread,
depending on the whether the underlying attempts to call anything that
requires the thread running the window. This is why it is risky to
touch the dialog outside of the main thread. You can never be certain
how or what the effect of attempting to update a dropdown, changing
some window text, or another similar operation will be from the worker
thread. So, to avoid it all together, you just pass messages with what
you need the other thread to do, and avoid the risk all together.

Passing pointers to the objects between threads won't cause problems by
itself. It's the actual use of the object pointed to that causes the
issue, so as long as all you are doing is PostMessage, you should be
fine (Assuming the pointer is valid)



Thread Proc Parameter

by Ed Weir (ComCast) » Fri, 24 Mar 2006 06:30:53 GMT




| >From what I got from Microsoft there is a bug where you can't set the
| timeout for those functions and they don't recognize when the
| connection they are using is dropped, not in the CE world anyway.
|

Have you tried IOCtl()? Lookup FIONREAD and use a timeout algorithm... dead
sockets aren't hard to detect.

Cheers!
- Ed.



Similar Threads

1. linq to sql for stored proc with user defined table as parameter - CSharp/C#

2. executing a Stored Proc with optional Parameters

Hi ,

"Roger" < XXXX@XXXXX.COM > wrote in message 
news: XXXX@XXXXX.COM ...
> Using OLEDB command object, I have a stored proc that take 3 paramters. 
> But,
> all parameters are set with a default value.
>
> In T-SQL (Query Analyzer) I can call "exec StoredPRoc @parm1 = value"
> and the other 2 are assigned null values.
>
> But, using ADO.Net, when I assign the commandtext property with the SP 
> name,
> would i have to assign all three but only pass the value to the parameter 
> I
> want?

Did you try it?

AFAIK you can do so, pass the parameter you want (make sure to select the 
correct name ) and it should od the trick.



-- 
Ignacio Machin
machin AT laceupsolutions com 


3. Default stored proc parameters? - CSharp/C#

4. Crystal Reports - Default Stored Proc Parameter?

Greetings,

I have used Crystal for over 5 years now.  I have developed a number
of report viewing sub-applications (nothing too extravagant). 
Crystal's object model is not developer friendly.  Many of you who
debug your Crystal apps in .NET will no doubt have witnessed the
gobbledygook visible when viewing the tree view of the ReportDocument
object.

On issue that I have been unable to resolve FOR SEVERAL YEARS now is
the passing of null parameter values in order to use the default
stored proc values.

For example consider this stored proc's parameter declaration:

  CREATE PROCEDURE RptTransactions 
	@DateFrom 	as datetime = null,
	@DateTo 	as datetime = null,
	@StoreNo 	as smallint = null,
	@EmployeeNo 	as smallint = null,
	@WindowNo	as smallint = null,
	@DrawerID 	as int = null,
	@CategoryCode	as varchar(2) = null,
	@KindCode	as char(1) = null,
	@CheckCashing as bit = 0
  AS

My .NET application accepts preconfigured parameter strings like this:

@DateFrom{7/30/2004}@DateTo{8/11/2004}@StoreNo{73}@EmployeeNo{}@WindowNo{}@DrawerID{}@CategoryCode{}@KindCode{}@CheckCashing{}

As you can see a number of the parameters have blank values ("{}")
immediately following.  In the cases of these parameters, I pass
"null" (not DBNull.Value -- it throws an exception).  Pay special
attention to the @CheckCashing parameter.  The idea is that when the
Crystal Report receives null for the @CheckCashing parameter it will
in turn pass the null parameter to the stored
proc which will in turn default it to "0" as indicated for the default
value.  This does not happen.  It seems I have more problems with
boolean (bit) value parameter passing then with any other kind of
parameter passing.

I have been able to create two workarounds (band-aids that I hope to
properly resolve):

1. I created a function that parses the stored proc called by the
report and determines the default value so that I can apply it
directly to the crystal report.
2. I convert boolean fields to char(1) and pass "Y" or "N".

The funny thing is that this weird bool behavior is inconsistent. 
Some of my reports using booleans seem to work just fine.  I have
checked the report definitions as well and whether or not these
parameters have default values assigned within the report itself seems
to have no bearing on the outcome.

Any ideas?

I have been working around these issues for some time and I hope to
put them to bed the right way!  Thanks for your consideration of this
issue.

Mario T. Lanza
Clarity Information Architecture, Inc.

5. How to test null date output parameter returned from a stored proc - CSharp/C#

6. Stored Proc w/ Parameters

I see two ways to fill a dataset with the results of a stored procedure:

1. Create a SqlCommand object with the text ...

...
sqlConn.Open();
String strSql = "exec p_my_sproc @intParam = " + intParam.ToString() ;
SqlCommand sqlComm = new SqlCommand(strSql,sqlConn);

or

2. Create a SqlCommand object using SqlParameter class.

What is going on behind the scenes that would make option 2 more worthwhile?
Under what circumstances?

Thanks in advance!
Mark


7. Argument problem with an XSD stored proc with output parameter - CSharp/C#

8. XML input Parameter C# (Stored Proc)