Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

CAsyncSocket in a DLL, frequent crashes on close in DetachHandle

Posted on 2006-03-30
17
Medium Priority
?
969 Views
Last Modified: 2013-11-20
I have encountered a problem with closing CAsyncSocket. Crash is reported in sockcore.cpp, and it's an assert in CAsyncSocket::DetachHandle (my source files seem a bit out of sink with the pdb files, so I'm not too clear on where exactly).

Here are some details:

I'm writing a DLL that's loaded by a service. The DLL is using CAsyncSocket to communicate with the server. The DLL exports a few interfaces. I know that funcStart will be called first, and funcStop as the last one. Therefore, I do Create() in funcStart, and do ShutDown(2) and Close() in funcStop.

I also created a "listening" thread that is basically an infinite while loop, which checks if there is anything to receive (and processes it, if anything is there), then sleeps for a while, allowing other processing. The thread is created in DllMain on DLL_PROCESS_ATTACH and terminated on DLL_PROCESS_DETACH, i.e. this is not an UI (CWinThread-derived) thread.

The socket is a global variable (protected by its own mutex), that is used by the "listening" thread between calls to funcStart and funcStop.

The problem/crash happens on Close(), 1 out of 2 times approximately. I have no other issues, i.e. Send() and Receive() work fine.

From what I read on discussion groups, the problem could be in the fact that I'm using a socket in different threads. Now, if I created it in the main, and am destroying it in the main, I do not see how anything with handle tables could be messed up (if that's the issue here at all).

Help welcome and greatly appreciated! Thanks!


0
Comment
Question by:aquarius003
  • 8
  • 6
  • 3
17 Comments
 

Author Comment

by:aquarius003
ID: 16337849
The cause seems to be in CAsyncSocket::AsyncSelect(), since the socket window is NULL:

ASSERT(pState->m_hSocketWindow != NULL);
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 1000 total points
ID: 16338548
As I indicated in your other thread (http:/MFC/Q_21783532.html#16261925 in which you gave me a grade of "B"), it is necessary to call AfxSocketInit() in each thread.  

You will also find great success if you do all of the socket activities in the one thread... create, open, read, write, close, destroy.  MFC socket handling is *not* threadsafe and the thread-unsafe parts of it are behind the scenes and hard to avoid -- unless you do *everything* in the thread.

Some related info in here:

    FIX: An unhandled exception occurs when you use MFC sockets in secondary threads
    in an MFC Visual C++ 6.0 application
    http://support.microsoft.com/kb/q193101/

-- Dan(y)
0
 

Author Comment

by:aquarius003
ID: 16339808
Hi Dan,

Sorry for the B, but that didn't really solve any of my issues. I just thought it was a most useful of all answers, and wanted to close the thread because I abandoned the strategy I was pursuing then.

I tried UI threads, and gave up (that's what the article you're mentioning was related to), switching to CAsyncSocket, as you can see from my current issue. :)

Among other things, I tried your advice and called AfxSocketInit from both the main and 'listener' thread. I also tried killing off the listening thread before closing the socket, doing ShutDown(2) on it before closing it.... nothing changed my predicament. Closing socket still freezes/crashes the calling service.

Tomorrow morning (it's 1am in my village, and time for bed) I'm going to take a look at the MS link you included, I haven't came across it before. I was actually just thinking that I can do away with that puny miserable listening thread as well, set up a CWnd timer and check on the Receive() from the handler a few times a second. And see what kind of issue I'll encounter next with this (nope, I don't think my tempest in a bottle is over yet).

And btw, I do not seem to have any thread-safety issues -  I did secure the use of the socket by wrapping it in a mutex-secured sentinel. Why is the freaking sink window NULL in the thread that created the socket in the first place?? Oh, well.

Thanks for the reply (and sorry about the B :)!!

Sandra
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 22

Assisted Solution

by:mahesh1402
mahesh1402 earned 1000 total points
ID: 16339811
try making call to 'AsyncSelect(0)' in your derived classes destructor OR

Try overriding CAsyncSocket::Close as follows:

void CMySocket::Close()
{
    AsyncSelect(0);
    CAsyncSocket::Close();
}


MAHESH
0
 

Author Comment

by:aquarius003
ID: 16339853
Oh, forgot one thing: I did try the 'do everything from one thread' approach with UI thread and CSocket, and as everyone who's still awake and reading at this point in my story knows, it didnt' work. I guess it's along the lines with my CWnd timer idea, which is the only way I can see at the moment (and I've been known to suffer from selective blindness) to get all work done within one thread.

To be honest, sounds like not too smart thing to do. Any other smart-sounding idea will be given serious consideration.

Good nite!
0
 

Author Comment

by:aquarius003
ID: 16339860
Hi Mahesh,

I did try AsyncSelect thingie as well. I even think I got the idea from something very similar you mention in your post (probably posted by you as well :). Nope, didn't work. Thanks, though!

Sandra
0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 16339878
Well Where you are calling CAsyncSocket::Close()  ? in ExitInstance() ?? if so try calling it earlier CMainFrame::OnClose might be a good place.

MAHESH
0
 

Author Comment

by:aquarius003
ID: 16339902
Hi Mahesh, you remind me of myself, I always rush ahead without considering (or in your case,  reading) things fullly. :)

Here is a part of my original post:

"The DLL exports a few interfaces. I know that funcStart will be called first, and funcStop as the last one. Therefore, I do Create() in funcStart, and do ShutDown(2) and Close() in funcStop."

So, you can see that it's called way before CWinApp is destructed (there ain't no CMainFrame here, it's a DLL).

0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 16340243
You are getting assertion on which line of sockcore.cpp ?
0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 16340361
>>The socket is a global variable

Its necessary to make socket object global ?  Can you move it inside thread ??

http://www.experts-exchange.com/Programming/Programming_Languages/MFC/Q_10132623.html <=====


MAHESH
0
 

Author Comment

by:aquarius003
ID: 16342444
Assert happens in CAsyncSocket::AsyncSelect(), at ASSERT(pState->m_hSocketWindow != NULL).

I'll try Attach()/Detach() thingie when the socket it passed between the threads.

I don't see the point in making it local to the thread, since the thread is doing the listening part only. Sending is done from the main thread: whenever one of the exported functions is called, I have to send a specific message, and  I'd end up having to pass it out to the main one anyhow. I don't think I could use thread notification for this, since I don't think I can pass parameters with it.

I shall try and let you know!
0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 16342582
and you are sending messages using PostThreadMessage ?

MAHESH
0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 16342677
>>Assert happens in CAsyncSocket::AsyncSelect(),

you're calling CAsyncSocket::Create method in the context of the same thread that calls CAsyncSocket::AsyncSelect ?

MAHESH
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16344584
>> The thread is created in DllMain on DLL_PROCESS_ATTACH
 
You should not do complex tasks such a creating threads and/or sockets in your DLL_PROCESS_ATTACH handler.  The normal procedure is to have the program that accesses your DLL functions to first call an Intitialize() or Setup() or Open() fn of some type.

    DllMain
    http://msdn.microsoft.com/libraryen-us/dllproc/base/dllmain.asp
0
 

Author Comment

by:aquarius003
ID: 16347058
Dan, what's wrong with starting/killing a thread in DllMain???

Okay, I hope this was my last issue with the darn DLL. I was fiddling with it all day, and even when I got rid of threads, the thing just asserted randomly on the closing time. I have no idea why. The thing is, you can't really monitor the sink window for a change (at what point it gets set to NULL) - it won't let you step into whichever function it is that's called internally to retrieve state structure (_afxGetStateOrSomething).

Anyhow....

I switched to WinSock, and it's working just fine. No issues any more. I just wasted two full days on CAsyncSocket issues. Using MFC sockets gave me absolutely no advantage, and I ended up with a whole bunch of headaches. On the positive side, I actually learned a lot, even though I detested the unpleasantness of the process.

Thanks for all you advices. I shall split the points between two of you. I really do appreciate your efforts with this convoluted issue. In a way, I was in a way led out of the forest with your "you shouldn't do that" kind of advice. :)

Ta-ta!
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 16347367
>> Dan, what's wrong with starting/killing a thread in DllMain???

From
    DllMain
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecoreos5/html/wce50lrfdllmain.asp
 >> For example, calling User, Shell, COM, and Windows Sockets functions (or functions
       that call these functions) can cause access violation errors, because their DLLs call
       LoadLibrary to load other system components.

That warning is actually for WinCE developers, but it is scary enough to make *me* (at least) want to avoid it in all programs.  Other MSDN pages warn against calling CoCreateInstance in DllMain and the specific warning is to avoid doing anything that might end up loading additional libaries.  Similar warnings indicate that care must be taken when unloading.  See the raft of "be careful here!" type warnings at the end of:
     http://msdn.microsoft.com/library/en-us/dllproc/base/dllmain.asp
0
 

Author Comment

by:aquarius003
ID: 16348548

Good pointers, thanks.

If I read them correctly, the problems happen only if you cause any of the above during the startup of the thread (i.e. while still in the DllMain).

I believe I'm in clear, since the thread I start on DLL_PROCESS_ATTACH doesn't do socket initialization or has anything to do with creating it. WSAStartup and socket creation is done from the main thread, when one of the exported function is called , way after the thread has been created. Before the time that socket is initialized and connected, the listening thread is spinning empty cycles.

If I am wrong, and my setup _is_ potentially unstable, the only remaining option I see would be to switch to timed events, to support listening. I'm not too keen on this, but it will be considered.

Thank you very much again!!
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
In this post we will learn different types of Android Layout and some basics of an Android App.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Suggested Courses

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question