`boost::filesystem`线程安全吗?

问题描述 投票:0回答:1

这是我在 Debian 稳定系统上观察到的以下情况:

% valgrind --tool=drd ./threads
==1368067== drd, a thread error detector
==1368067== Copyright (C) 2006-2020, and GNU GPL'd, by Bart Van Assche.
==1368067== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==1368067== Command: ./threads
==1368067==
==1368067== Thread 3:
==1368067== Conflicting load by thread 3 at 0x048cc208 size 8
==1368067==    at 0x48C1CB6: size (basic_string.h:1064)
==1368067==    by 0x48C1CB6: boost::filesystem::path::end() const (path.cpp:737)
==1368067==    by 0x48C2331: boost::filesystem::path::compare(boost::filesystem::path const&) const (path.cpp:178)
==1368067==    by 0x48C26D9: operator== (path.hpp:771)
==1368067==    by 0x48C26D9: boost::filesystem::path::extension() const (path.cpp:353)
==1368067==    by 0x48C284E: boost::filesystem::path::replace_extension(boost::filesystem::path const&) (path.cpp:238)
==1368067==    by 0x10B449: run(void*) (in /home/mathieu/Perso/PublicRep/cxx/boost/bin/threads)
==1368067==    by 0x484CD34: ??? (in /usr/libexec/valgrind/vgpreload_drd-amd64-linux.so)
==1368067==    by 0x4B90133: start_thread (pthread_create.c:442)
==1368067==    by 0x4C0FA3F: clone (clone.S:100)
==1368067== Allocation context: BSS section of /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.74.0
==1368067== Other segment start (thread 2)
==1368067==    (thread finished, call stack no longer available)
==1368067== Other segment end (thread 2)
==1368067==    (thread finished, call stack no longer available)
==1368067==

这是我用来重现此内容的 C++ 代码:

% cat threads.cxx
#if 0
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <boost/filesystem/path.hpp>
namespace fs = boost::filesystem;
#endif

#include <pthread.h>

#define N 32

static void* run(void* arg) {
  uintptr_t job = (uintptr_t)arg;
  fs::path path{"/foo/bar.jpg"};
  path.replace_extension("png");
  return nullptr;
}

int main(int argc, char* argv[]) {
  uintptr_t i;
  int rc;
  pthread_t threads[N];
  for (i = 0; i < N; ++i) {
    if ((rc = pthread_create(threads + i, nullptr, run, (void*)i))) {
      return rc;
    }
  }

  for (i = 0; i < N; ++i) {
    if ((rc = pthread_join(threads[i], nullptr))) {
      return rc;
    }
  }
  return 0;
}

我一直在审查 boost 1.74 代码库,但必须承认我无法理解为什么 valgrind 会在这里将其视为冲突负载。有人可以帮我检查一下

boost::filesystem
代码库来检查这里是否确实存在线程安全问题吗?我无法使用
std::filesystem
重现该问题(请参阅代码中的#ifdef)。

供参考:

  • 系统:Debian稳定版
  • 编译器:g++ 12.2.0-14
  • Valgrind:3.19.0

更新:

% make && valgrind --tool=helgrind ./threads
[100%] Built target threads
==1455067== Helgrind, a thread error detector
==1455067== Copyright (C) 2007-2017, and GNU GPL'd, by OpenWorks LLP et al.
==1455067== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==1455067== Command: ./threads
==1455067==
==1455067== ---Thread-Announcement------------------------------------------
==1455067==
==1455067== Thread #3 was created
==1455067==    at 0x4BEEA2F: clone (clone.S:76)
==1455067==    by 0x4BEF878: __clone_internal (clone-internal.c:83)
==1455067==    by 0x4B6ED6F: create_thread (pthread_create.c:295)
==1455067==    by 0x4B6F82C: pthread_create@@GLIBC_2.34 (pthread_create.c:831)
==1455067==    by 0x484B5D7: ??? (in /usr/libexec/valgrind/vgpreload_helgrind-amd64-linux.so)
==1455067==    by 0x10B2AD: main (in /home/mathieu/Perso/PublicRep/cxx/boost/bin/threads)
==1455067==
==1455067== ---Thread-Announcement------------------------------------------
==1455067==
==1455067== Thread #2 was created
==1455067==    at 0x4BEEA2F: clone (clone.S:76)
==1455067==    by 0x4BEF878: __clone_internal (clone-internal.c:83)
==1455067==    by 0x4B6ED6F: create_thread (pthread_create.c:295)
==1455067==    by 0x4B6F82C: pthread_create@@GLIBC_2.34 (pthread_create.c:831)
==1455067==    by 0x484B5D7: ??? (in /usr/libexec/valgrind/vgpreload_helgrind-amd64-linux.so)
==1455067==    by 0x10B2AD: main (in /home/mathieu/Perso/PublicRep/cxx/boost/bin/threads)
==1455067==
==1455067== ----------------------------------------------------------------
==1455067==
==1455067== Possible data race during read of size 8 at 0x48AB208 by thread #3
==1455067== Locks held: none
==1455067==    at 0x48A0CB6: size (basic_string.h:1064)
==1455067==    by 0x48A0CB6: boost::filesystem::path::end() const (path.cpp:737)
==1455067==    by 0x48A1331: boost::filesystem::path::compare(boost::filesystem::path const&) const (path.cpp:178)
==1455067==    by 0x48A16D9: operator== (path.hpp:771)
==1455067==    by 0x48A16D9: boost::filesystem::path::extension() const (path.cpp:353)
==1455067==    by 0x48A184E: boost::filesystem::path::replace_extension(boost::filesystem::path const&) (path.cpp:238)
==1455067==    by 0x10B449: run(void*) (in /home/mathieu/Perso/PublicRep/cxx/boost/bin/threads)
==1455067==    by 0x484B7D6: ??? (in /usr/libexec/valgrind/vgpreload_helgrind-amd64-linux.so)
==1455067==    by 0x4B6F133: start_thread (pthread_create.c:442)
==1455067==    by 0x4BEEA3F: clone (clone.S:100)
==1455067==
==1455067== This conflicts with a previous write of size 8 by thread #2
==1455067== Locks held: none
==1455067==    at 0x48A03B0: _M_length (basic_string.h:229)
==1455067==    by 0x48A03B0: _M_set_length (basic_string.h:267)
==1455067==    by 0x48A03B0: _M_construct<char const*> (basic_string.tcc:247)
==1455067==    by 0x48A03B0: basic_string<> (basic_string.h:642)
==1455067==    by 0x48A03B0: path (path.hpp:171)
==1455067==    by 0x48A03B0: boost::filesystem::detail::dot_path() (path.cpp:698)
==1455067==    by 0x48A16CE: boost::filesystem::path::extension() const (path.cpp:353)
==1455067==    by 0x48A184E: boost::filesystem::path::replace_extension(boost::filesystem::path const&) (path.cpp:238)
==1455067==    by 0x10B449: run(void*) (in /home/mathieu/Perso/PublicRep/cxx/boost/bin/threads)
==1455067==    by 0x484B7D6: ??? (in /usr/libexec/valgrind/vgpreload_helgrind-amd64-linux.so)
==1455067==    by 0x4B6F133: start_thread (pthread_create.c:442)
==1455067==    by 0x4BEEA3F: clone (clone.S:100)
==1455067==  Address 0x48ab208 is 8 bytes inside data symbol "_ZZN5boost10filesystem6detail8dot_pathEvE7dot_pth"
==1455067==
==1455067== ----------------------------------------------------------------

更新2:

以下代码对于多线程应用程序是否可以接受:

Thread 2 "threads" hit Breakpoint 2, boost::filesystem::detail::dot_path () at libs/filesystem/src/path.cpp:698
(gdb) list
693         const path&  dot_path()
694         {
695     #   ifdef BOOST_WINDOWS_API
696           static const fs::path dot_pth(L".");
697     #   else
698           static const fs::path dot_pth(".");
699     #   endif
700           return dot_pth;
701         }
702
c++ multithreading boost valgrind boost-filesystem
1个回答
0
投票

看起来我可以使用简单的技巧让症状消失:

int main(int argc, char* argv[]) {
  uintptr_t i;
  int rc;
  fs::path p{"foo.bar"};
  p.extension(); // single-thread init for dot_path

之后

drd
helgrind
看起来都很开心。

© www.soinside.com 2019 - 2024. All rights reserved.