2017-04-10 62 views
0

我有一个用OpenMP实现的客户端应用程序。该程序在收到SIGINT信号时终止,但在这种情况下,它应该首先向服务器发送一条消息,指出用户已注销。我已经成功地实现了消息传递,但之后我一直无法让程序终止。收到SIGINT信号后退出程序

这里是我的代码的并行部分:

#pragma omp parallel num_threads(4) 
{ 
    #pragma omp sections 
    { 
     #pragma omp section 
     { 
      while(1) 
      { 
       char pom[1000]; 
       fgets(pom, 1000, stdin); 
       if (strlen(pom) != 1) 
       { 
        char * buffer; 
        buffer = message(username, pom); 
        if (send(client_socket, buffer, strlen(buffer), 0) < 0) 
        { 
         callError("ERROR: cannot send socked"); 
        } 
        bzero(pom, 1000); 
        free(buffer); 
       } 
      } 
     } 
     #pragma omp section 
     { 
      char buffer[4096]; 
      char * data; 
      ssize_t length; 
      int received = 0; 
      int data_cap = 4096; 
      while(1) 
      { 
       data = calloc(BUFFER_LEN, sizeof(char)); 
       while ((length = read(client_socket, buffer, BUFFER_LEN)) > 0) 
       { 
        received += length; 
        if (received > data_cap) 
        { 
         data = realloc(data, sizeof(char) * data_cap * 2); 
         data_cap = data_cap * 2; 
        } 
        strcat(data, buffer); 
        if (!isEnough(data)) 
        { 
         break; 
        } 
       } 
       printf("%s", data); 
       free(data); 
       bzero(buffer, BUFFER_LEN); 
       data_cap = 4096; 
       received = 0; 
       length = 0; 
      } 
     } 
     #pragma omp section 
     { 
      void sig_handler(int signo) 
      { 
       char * welcome1 = calloc(strlen(username) + 13, sizeof(char)); 
       strcat(welcome1, username); 
       strcat(welcome1, " logged out\r\n"); 
       if (send(client_socket, welcome1, strlen(welcome1), 0) < 0) 
       { 
        callError("ERROR: cannot send socked"); 
       } 
       free(welcome1); 
      } 

      while (1) 
      { 
       if (signal(SIGINT, sig_handler) == SIG_ERR) 
        printf("\ncan't catch SIGINT\n"); 
       while (1) 
        sleep(1); 
      } 
     } 
    } 

我怎样才能使捕捉信号后程序终止?

回答

0

你的程序有几个严重的问题。

首先,您试图将信号处理函数定义为嵌套函数。 C没有嵌套函数。你的代码编译完全意味着你依赖于语言扩展,并且将它与信号处理并置是特别不明智的。

您在信号处理程序中调用函数callError()。目前还不清楚这个功能是否是异步信号安全的。您可以在信号处理程序中调用函数calloc()strcat()free()。这些绝对是而不是异步信号安全,不能从信号处理程序内部调用。

您将四个线程添加到您的并行构建中,但只提供三个要运行的部分。

你把所有的并行部分放入无限循环(所以当然是程序在捕获已经安装了处理程序的信号时不会终止)。

您不一致地检查函数调用的返回值。


您的整体策略似乎很混乱。一般来说,执行干净的异步关闭 - 即导致线程终止操作以响应不同线程或信号处理程序的操作 - 涉及设置共享标志,以便定期关闭的线程检查确定是继续还是退出。您可以安全地从信号处理程序中设置这样的标志,前提是其类型为volatile sig_atomic_t。此外,信号处理程序应尽可能少地执行工作,并且它们允许调用的系统功能仅限于指定为同步信号安全的那些系统功能。此外,他们可能会使用一个小堆栈,您应该小心不要冒险。

此外,无论等待安装信号处理程序,直到进入OMP并行块之后,没有任何优势,也没有优势让信号处理程序将终止消息发送到服务器本身。

因为你似乎心满意足奉献一个线程的信号处理,我建议你用它来接受SIGINT同步,通过sigwait()或与其相关的功能之一。该线程可以触发OMP的取消功能 - 请参见cancel-var ICV和cancel构造。其他线程将需要合作 - 请参阅cancellation point构造。由于您没有提供其他方式来退出并行部分,因此您可以将注销消息从正常(不是信号处理程序)代码发送到服务器,紧跟在并行区域之后。

+0

谢谢我会尝试它:) – krakra

0

我只是重写我的代码,它工作正常,但我知道在线程中退出整个程序是个坏主意。它wokrs罚款,但Valgrind是调用可能MEM泄漏,它不断地免费较少,这一计划alocates总堆的使用情况:40个allocs,34周的FreeS我真的不明白我这样做如何选择性退出此程序:

#pragma omp parallel num_threads(2) 
{ 
    #pragma omp sections 
    { 
     #pragma omp section 
     { 
      static volatile int keepRunning = 1; 
      void intHandler(int dummy) 
      { 
       keepRunning = 0; 
       char * welcome1 = calloc(strlen(username)+13,sizeof(char)); 
       strcat(welcome1,username); 
       strcat(welcome1," logged out\r\n"); 
       if(send(client_socket,welcome1,strlen(welcome1),0) < 0) 
       { 
        callError("ERROR: cannot send socked"); 
       } 
       free(welcome1); 
       exit(130); 
      } 
      signal(SIGINT, intHandler); 
      char *str, c; 
      int i = 0, j = 1; 
      char * buffer; 
      while(keepRunning) 
      { 
       str = (char*)malloc(sizeof(char)); 
       while((c = getc(stdin)) != '\n'){ 

        str = (char*)realloc(str, j * sizeof(char)); 
        str[i] = c; 
        i++; 
        j++; 
       } 
       str = (char*)realloc(str, j * sizeof(char)); 
       str[i] = '\0'; 
       if(strlen(str)!=0) 
       { 
        buffer = message(username,str); 
        if(send(client_socket,buffer,strlen(buffer),0) < 0) 
        { 
         callError("ERROR: cannot send socked"); 
        } 
        free(buffer); 
       } 
       free(str); i = 0; j = 1; 
      } 
     } 
     #pragma omp section 
     { 
      static volatile int keepRunning = 1; 
      void intHandler(int dummy) { 
       keepRunning = 0; 
       char * welcome1 = calloc(strlen(username)+14,sizeof(char)); 
       strcat(welcome1,username); 
       strcat(welcome1," logged out\r\n"); 
       if(send(client_socket,welcome1,strlen(welcome1),0) < 0) 
       { 
        callError("ERROR: cannot send socked"); 
       } 
       free(welcome1); 
       exit(130); 
      } 
      char buffer[4096]; 
      char * data; 
      ssize_t length; 
      int received = 0; 
      int data_cap = 4096; 
      signal(SIGINT, intHandler); 
      while(keepRunning) 
      { 
       data = calloc(BUFFER_LEN,sizeof(char)); 
       while ((length = read(client_socket, buffer, BUFFER_LEN)) > 0) 
       { 
        received += length; 
        if (received > data_cap) 
        { 
         data = realloc(data,sizeof(char) * data_cap * 2); 
         data_cap = data_cap * 2; 
        } 
        strcat(data, buffer); 
        if(!isEnough(data)) 
        { 
         break; 
        } 
       } 
       printf("%s", data); 
       free(data); bzero(buffer,BUFFER_LEN); data_cap = 4096; received = 0; length = 0; 
      } 
     } 
    } 
}