2013-08-21 32 views
1

我正在编写一个多线程服务器应用程序,它回应客户端发送的任何内容。我为每个新客户产生一个线程。我已经使用了一个while(1)循环来无限期地处理连续的客户端(不完全不确定,我强制地将其限制为64,之后它拒绝任何新的连接)。现在我需要在我的服务器应用程序中处理Ctrl + C信号。从signal_handler例程中取消main()线程的正确方法是什么?

一个问题是它的not recommended在多线程应用程序中使用signal()

然而,即使我用它使用method already discussed at SO这是我需要做的,赶上SIGINT信号(从按Ctrl + C):
1)服务器不应该再接受更多的客户。
2)当前连接到服务器应该继续,除非客户端选择断开连接。

我的信号处理函数是:

void Ctrl_C_handler(int sig) 
{ 
    if(sig == SIGINT)  // Ctrl+C 
    { 
     printf("Ctrl+C detected by server !!\n"); 
     printf("No more connections will be accepted!!"); 
     pthread_cancel(main_thread_id); 
    } 
} 

的方法我建议里面主要使用()取消线程是:

// Method 1 
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 
while(1) 
{ 
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 

      // .. 
      // client handling 
      // .. 
} 

// Method 2 

while(1) 
{ 
    pthread_testcancel();  // Create Cancellation point 
      // .. 
      // client handling 
      // .. 
} 

// Method 3 

while(1) 
{ 
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 
    pthread_testcancel(); 
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 
      // .. 
      // client handling 
      // .. 
} 

原因为什么我使用pthread_cancel()

根据this link th e线程将最终使用pthread_exit()(满足要求1)终止。由于NOTES section of pthread_exit()解释说它允许其他线程继续执行(要求2完成)。

现在,如果我是正确的,直到在这里,

哪种方法是最好的线程的取消。
我选择的方法3,因为:

(记过)方法1:异步线程取消并不安全(因为我在SO答案看见)如果线程分配内存,以及其他一些原因

(记过)方法2:根据this link,有很多其他功能也可以作为取消点,我将在我的代码中使用一些功能。方法3:与方法2类似,但更安全,因为其他取消点将不会被激活,因为线程被取消禁用。

请告诉我,我的方式是否正确?它的错误,除了使用pthread_cancel()之外,还有其他更好的方法来处理Ctrl + C吗?

回答

1

我建议避免取消。

取而代之的是,注册一个SIGINT处理程序,它关闭()服务器的侦听套接字。 (为此,请使用sigaction。)在关闭套接字后,主线程可以正常退出,并保持任何客户端线程在运行。

E.g.伪代码:

static int listen_fd = -1    // server socket 

void handle_SIGINT(int s):    // Requirement 1 
    if listen_fd >= 0: 
    close(listen_fd) 
    listen_fd = -1 

int main(...): 
    listen_fd = new_listening_socket(...) 
    block_signal(SIGINT) 
    trap_signal(SIGINT, handle_SIGINT) // again, calls sigaction 

    while 1: 
    unblock_signal(SIGINT) 
    new_client = accept(listen_fd) 
    block_signal(SIGINT) 

    if new_client < 0:     // Requirement 1, also general error handling 
     break 

    spawn_worker_thread(new_client)  // probably attr PTHREAD_CREATE_DETACHED 

    pthread_exit(NULL)     // Requirement 2 
    return 0        // not reached 

根据需要,您当然可以包含更多微妙的错误处理,清理例程等。

+0

我在想,pthread_cancel()不应该在正常情况下使用,但无法拿出更优雅的东西(正如您的方法),感谢解决方案。 –

+0

我还发现了一个[类似的代码](http://www.cs.cf.ac.uk/Dave/C/node32.html#SECTION003240000000000000000)。此代码使用完全不同的线程进行信号处理。 –

+0

**一个简单的问题**我在使用此方法时注意到:当调用accept()时,它可能会复制listen_fd的值,并使用它接受客户端。因此,即使'listen_fd'由signal_handler关闭,而主线程被阻塞(通过'accept()'),'accept()'调用可能会成功返回,因此具有正确的'client_fd'。解决方案:在accept()后也检查'listen_fd'的有效性。 –

相关问题