为什么它不是线程安全以及如何获得线程安全?

Why it's not thread safety and how to get it thread safety?

本文关键字:线程 安全 何获得 为什么      更新时间:2023-10-16

FCGI中有一些函数叫做"getRequestContent()"。它只是获取通过网络浏览器发布的数据。因此,我们的 c++ 应用程序类似于为 Web 客户端服务的守护进程。我想我对不是"线程安全"功能有某种问题:

/**
 * Note this is not thread safe due to the static allocation of the
 * content_buffer.
 */
std::string getRequestContent(const FCGX_Request &request)
{
    char *content_length_str = FCGX_GetParam("CONTENT_LENGTH", request.envp);
    unsigned long content_length = STDIN_MAX;
    if (content_length_str)
    {
        content_length = strtol(content_length_str, &content_length_str, 10);
        if (*content_length_str)
        {
            std::cerr << "Can't Parse 'CONTENT_LENGTH='"
                      << FCGX_GetParam("CONTENT_LENGTH", request.envp)
                      << "'. Consuming stdin up to " << STDIN_MAX << "n";
        }
        if (content_length > STDIN_MAX)
        {
            content_length = STDIN_MAX;
        }
    }
    else
    {
        content_length =
            0;  // Do not read from stdin if CONTENT_LENGTH is missing
    }
    char *content_buffer = new char[content_length];
    std::cin.read(content_buffer, content_length);
    content_length = std::cin.gcount();
    do
        std::cin.ignore(1024);
    while (std::cin.gcount() == 1024);
    std::string content(content_buffer, content_length);
    delete[] content_buffer;
    return content;
}

请解释为什么它不是线程安全代码?我们这里有什么问题?如何获得线程安全?:)

主要问题是,就像评论所说,有一个静态分配的缓冲区。如果两个线程在该缓冲区上同步工作,则很可能会获得竞争条件,因此必须避免这种情况。

这意味着要么修复FCGX_GetParam(我怀疑这是一个好主意,因为它是第三方库)要么同步对它的访问:

//some common mutex
std::mutex mtx;
std::string getRequestContent(const FCGX_Request &request)
{
  std::string content_length_str;
  {
    lock(mtx); //guard every action on the static buffer with this lock
    char *content_length_cptr = FCGX_GetParam("CONTENT_LENGTH", request.envp);
    content_length_str = content_length_cptr; //copy the content of the buffer
  } //unlock the mutex, you dont work on the buffer hence forth  
  unsigned long content_length = 0;
  if (!content_length_str.empty()) try {
    content_length = boost::lexical_cast<unsigned long>(content_length_str);
    if (content_length > STDIN_MAX)
    {
      content_length = STDIN_MAX;
    }
  }
  catch(boost::bad_lexical_cast const&)
  {
    std::cerr << "Can't Parse 'CONTENT_LENGTH='"
              << content_length_str
              << "'. Consuming stdin up to " << STDIN_MAX << "n";
    content_length = STDIN_MAX;
  }
  // the rest as it was...
}
char * content_length_str = FCGX_GetParam( "CONTENT_LENGTH", request.envp );

这一行可能意味着两件事:

如果函数返回由 alloc/calloc 分配的块,则您正在泄漏内存或者函数使用静态缓冲区。那不是线程安全的。考虑到评论,我猜这是第二种选择。