Two ways to terminate blocking socket thread gracefully

本文介绍两种优雅地关闭阻塞Socket线程的方法:一是外部关闭Socket,通过关闭Socket来取消所有线程中的阻塞调用;二是使用全局变量控制Socket线程的循环,利用select()函数监测读写请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

When writing the socket program with blocking socket functions, in most cases you need to start a thread to accept connection or write and read data.

Here are basic ways to end a thread:

    1, Use global variable as a flag to end loop. The variable can be the SOCKET, like

    while (sock != INVALID_SOCKET) …

    2, Use event or mutex. Just use WaitForSingleObject();

    3, call TerminateThread() by force.

 

In socket thread, the thread may be blocked, it’s not easy to terminate thread gracefully. “Graceful” or “elegantly”, I love those words. Don’t always use the TerminateThread, it’s too violent. Here I will introduce two ways to terminate blocking socket thread gracefully.

1.      close the socket out of thread

we need to keep the socket object, usually we restore them in a list. when we call closesocket(),Any pending blocking, asynchronous calls issued by any thread in this process are canceled. The steps are:

a)      shot down and close socket out of thread. Shutdown(), closesocket().

b)      Sleep for a while, to give the socket thread a chance to end.

c)      Blocking function then return INVALID_SOCKET when the socket is closed. End thread.

d)      Wait for the socket, here, the thread should end by itself,

e)      If wait timeout, terminate it. TerminateThread().

f)      Close thread hancle.

 

Notes:

a)      Don’t close the socket in thread.

b)      Just use the SOCKET handle as a flag to control loop.

c)      You need to restore the socket and thread handle

d)      It’s strange, by calling BIO_free() can’t terminate the blocking socket function.

 

Here is the code:

void ECMG::stopListen()

{

    if  (m_listenSock != INVALID_SOCKET) {     // SOCKET m_listenSock

 

       shutdown(m_listenSock, SD_BOTH);

       closesocket(m_listenSock);

       m_listenSock = INVALID_SOCKET;

 

       Sleep(60); // give the thread a chance to end

       if (m_listenThread != NULL) {

 

           // wait the thread to end

           if (WAIT_TIMEOUT == WaitForSingleObject(m_listenThread, 2000)) {

 

              // time out

              TerminateThread(m_listenThread, 0);

           }

           CloseHandle(m_listenThread);

           m_listenThread = NULL;

       }

    }

}

 

2.      Use global variable to terminate socket thread

In the blocking thread, in a loop, use select() to detect if there is any accept, read or write request. We can use a global variable such as socket object to control the loop. So if wanna terminate the thread, just turn on the flag. Obviously it’s not as so efficient.

Using steps:

a)      Setup fd_set

b)      Check the loop flag in a loop

c)      Call select(), if there is data, then process it.

notes:

before calling select(), you need to re initial the fd_set.

 

Here is the code:

#define DEFAULT_WAIT_TIME   100

DWORD WINAPI ECMG::rwThread(LPVOID lpParameter)

{

    ECMG *pthis = (ECMG *)lpParameter;

    BIO *cbio = pthis->m_bClient;

    int iLen;

    char buf[SO_MAX_MSG_SIZE] = {0};

    unsigned long ulthID = GetCurrentThreadId();

    fd_set fdRead  = {0};

    TIMEVAL    stTime;

    TIMEVAL    *pstTime = NULL;

 

    SOCKET s = (SOCKET)BIO_get_fd(cbio, 0);

    if (INVALID_SOCKET == s)

       return 0;

 

    stTime.tv_sec = DEFAULT_WAIT_TIME / 1000;

    stTime.tv_usec = DEFAULT_WAIT_TIME % 1000;

    pstTime = &stTime;

    FD_SET(s, &fdRead);

      

    while(cbio)

    {

       // notes that we need to initial fd_set every time.

       if (!FD_ISSET(s, &fdRead))

           FD_SET(s, &fdRead);

       int res = select(s+1, &fdRead, NULL, NULL, pstTime);

       if (res > 0) {

          

           memset(buf, 0, SO_MAX_MSG_SIZE);

           iLen = BIO_read(cbio, buf, SO_MAX_MSG_SIZE);

           if (0 == len || -1  == len) {

 

              ::PostMessage(pthis->m_hWnd, MSG_THREAD_EVENT, EVT_CONDROP, (LPARAM)cbio);

              break;

           }

           // process the message

           pthis->OnReceiveData(cbio, buf, len);

       }

       Sleep(0);

    }

 

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值