views:

269

answers:

3

I am trying to handle socket in different threads creating runtime failure. See following code.

void MySocket::Lock()
{
    m_LockCount++;

    if( m_LockCount )
    {
     CSocket::Create( 8080 );
    }
}

void MySocket::Unlock()
{
    m_LockCount--;

    if( !m_LockCount )
    {
     CSocket::Close();
    }
}

I am calling Lock() from one thread and Unlock() from other. When it executes CSocket::Close() it gives an exception.

I googled for this bug and got some reasons. This happens because; a CSocket object should be used only in the context of a single thread because the SOCKET handle encapsulated by a CAsyncSocket object is stored in a per-thread handle map. They are also suggesting a solution by sharing SOCKET handles between threads (http://support.microsoft.com/kb/175668). But this is not possible in my case since I am excepting some notification callback which will not work with above solution. Can anybody suggest a mechanism to share CSocket among threads without effecting notification callbacks?

+3  A: 

You coould just use the socket directly and stop using the, obviously, flawed MFC implementation ...

Goz
I generally agree, but if that's not an option, see my answer.
Bob Murphy
+1  A: 

I would advise you to use some higher-level (and less buggy) socket API like Boost.Asio. Note that it does not make sockets thread-safe anyway (see there). You have to use some lock/unlock facility.

I am not sure i understand your question about sharing sockets among threads without using notification callbacks. Between threads T1 and T2, supposing T1 manages a socket, there are only two ways for T2 to become aware of a socket event. Either some notification launched by T1 or a question asked by T2 to T1, either on a regular basis or in a blocking call.

Benoît
Thanks. I can add some more details. Shared socket actually listening connections. So T1 shall call the CSocket::Create() and CSocket will start to listen. When T2 is started it will increment the m_LockCount. Now assume T1 has stopped. It will decrement m_LockCount. After that T2 has stopped. T2 will decrement m_LockCount to 0 and will call CSocket::Close(). Hope you understand the way I supposed to share.
Vadakkumpadath
"because the SOCKET handle encapsulated by a CAsyncSocket object is stored in a per-thread handle map" According to this, the handle to the socket would be lost if T1 exits so T2 should not be able to close it.
Gayan
+1  A: 

If, as you say, "a CSocket object should be used only in the context of a single thread," then there is no "mechanism to share CSocket among threads".

In other words, one of the threads needs to own the CSocket, and the others can't mess with it.

In such cases, the solution is to use an inter-thread messaging system. That way, one of the other threads can send a message to the owner saying, "Hey, buddy, close your socket!"

The details of how you would do that messaging depend entirely on the context of your program.

Bob Murphy