OpenMP取消部分

时间:2017-04-19 13:15:22

标签: c multithreading openmp

我在终止C程序中的部分时遇到问题。在一个线程中捕获SIGINT信号后,我想退出所有线程,但我真的不知道如何,因为我在这些循环中有无限循环。程序等待来自服务器或stdin的输入。所以我使用了信号处理程序。

我真的不知道我是否正确地这样做,而且我真的不明白OpenMP中的取消是如何工作的。我没有为此找到合适的教程或讲座。

我的任务是在捕获SIGINT信号后终止程序。但是当我在处理程序中使用exit()时,显然会留下未释放的内存。我会很高兴任何建议,谢谢。

#pragma omp parallel num_threads(2)
{
    #pragma omp sections
    {
        #pragma omp section
        {
            void intHandler(int dummy) 
            {
                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);
                #pragma omp cancel section
            }
            signal(SIGINT, intHandler);
            int i = 0, j = 1;
            while(1)
            {
                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)
                {
                    bufferIn = message(username,str);
                    if(send(client_socket,bufferIn,strlen(bufferIn),0) < 0)
                    {
                        callError("ERROR: cannot send socked");
                    }
                    free(bufferIn);
                }
                free(str); i = 0; j = 1; 
            }
        #pragma omp cancellation point section
        }
        #pragma omp section
        {
            void intHandler(int dummy) 
            {
                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);
                #pragma omp cancel section
            }
            signal(SIGINT, intHandler);
            char buffer[4096];
            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-1)) > 0)
                {
                    received += length;
                    buffer[length] = '\0';
                    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 cancellation point section
        }
    }

} 

1 个答案:

答案 0 :(得分:1)

这实际上非常复杂,但让我们开始简单。

  • #pragma omp cancellation point sections / #pragma omp cancel sections(请注意s)。

  • 您不能跨职能界限使用#pragma omp cancel 1

我们假设您可以使用取消方式取消,仅在特定取消点检查取消。因此,在阻止readgetc期间,您的线程不会被取消中断。

信号处理

每个进程都会设置信号处理程序,但信号结束的线程不确定。您不应该尝试从多个线程同时调用signalsignal的一些实现甚至就像多线程程序一样。相反,您应该使用sigaction,但在生成工作线程之前仍然会设置一次全局信号处理程序。

在信号处理程序中允许执行的操作存在某些限制。基本上,您不能访问任何非volatile sig_atomic_t类型的全局变量,只能调用async-signal-safe functions。你违反了信号处理程序的每一行。

特别是,在调用send(client_socket) 2 或同时调用read(client_socket)的另一个线程时,同一线程可能被中断时,调用read(client_socket)。不确定更糟糕的是,但即使send本身是 async-signal-safe ,我也会猜测,但建议的方式并不安全

你知道,在流程结束时有一些可达的内存绝对是你的问题。您甚至不允许致电exit(您可以致电_exit)。

通常的方法是设置一个类型为volatile sig_atomic_t的全局取消标志,并在信号处理程序中设置它,并在工作循环中检查它。这也适用于OpenMP部分/线程,但我建议为该标志的任何读/写添加#pragma omp atomic read/write seq_cst。这似乎是多余的,但我相当确定volatile sig_atomic_t仅保证信号中断的原子性,而不是多线程,特别是存储可见性。不幸的是,您仍遇到readgetc阻止的问题......

解决方案草图

因此,您必须使用某种机制使getc无阻塞或添加超时以使您的线程有机会检查取消标记。

poll可以为您提供更优雅的出路。您可以将readgetc的阻止部分替换为poll - 请记住,这会强制您将stdin专门用作文件描述符,而不是{{1} }。在准备中,您为每个部分创建一个管道,其输出包含在相应的FILE*中。在信号处理程序中,只有在生成管道之后才设置,您可以写入这些管道,指示线程应该关闭。如果poll显示那些特定stop-pipe-fds的活动,则退出循环,并在相应的线程中或在并行区域之后进行清理。根据需要应用同步。

很抱歉给你带来坏消息。它很复杂,没有简单,正确,可复制粘贴的解决方案。在任何情况下,OpenMP取消都不适合在这里使用。

1 :标准对此并不十分明确,它要求:

  

在执行可能被取消的构造期间,线程不得遇到孤立的取消点。也就是说,只能在该构造中遇到取消点,并且不得在其区域的其他地方遇到。

然而,由于取消区域本身是隐式取消点,我想可能暗示取消构造必须始终在显式并行区域的词法范围内。无论如何,poll不允许你使用取消构造编译像信号处理程序这样的函数。

2 :这实际上很好,但您必须至少手动恢复gcc,因为信号处理程序中的errno会覆盖它。 write应该方便地返回read