尽管使用了互斥体,C++ 并行程序中仍存在持续数据争用警告

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

尽管使用互斥锁,我在 C++ 并行程序中遇到了持续的数据争用警告。我已经使用 OpenMP 和互斥体实现了一个解决方案来同步对共享数据的访问,但我仍然收到有关数据争用的 ThreadSanitizer 警告。

代码概述:

我有一个程序,它从文件中读取数据,对其执行并行计算,并面临内存释放问题。代码的相关部分涉及使用 OpenMP 并行性和互斥体管理共享向量。

#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
#include <omp.h>
#include <mutex>

void readTextPointList(int n, int d, const std::string &strFileName, std::vector<std::vector<double>> &result)
{
  std::vector<std::vector<double>> PointList;
  std::string strLine;
  std::ifstream inFile(strFileName);

  if (inFile.is_open())
  {
    int i = 0;
    while (getline(inFile, strLine) && i < n)
    {
      if (strLine.size() != 0)
      {
        std::stringstream sin(strLine);
        std::vector<double> values(d);
        for (int j = 0; j < d; j++)
        {
          double aa;
          sin >> aa;
          values[j] = aa;
        }
        PointList.push_back(values);
        i++;
      }
    }
    inFile.close();

    // Use std::move to transfer ownership
    result = std::move(PointList);
  }
  else
  {
    std::cout << "Error: Unable to open file." << std::endl;
  }
}

std::mutex solveMutex;

void solve(std::vector<std::vector<double>> &data, size_t width, size_t start)
{
  std::vector<double> tuple(width);

  {
    std::lock_guard<std::mutex> lock(solveMutex); // Lock the critical section
    for (size_t i = 0; i < width; ++i)
    {
      tuple[i] = data[start][i];
    }
  }

  // No need to unlock explicitly; std::lock_guard takes care of it when it goes out of scope
}

auto main(int argc, char **argv) -> int
{
  if (argc < 2)
  {
    std::cout << "Usage: DIMENSIONALITY WINDOW" << std::endl;
    return 0;
  }
  size_t width = strtoul(argv[1], nullptr, 10);
  size_t datasize = strtoul(argv[2], nullptr, 10);

  // Read the data into a shared vector
  std::string filename = "mydata.txt";
  std::vector<std::vector<double>> data;

  readTextPointList(datasize, width, filename, data);

  int core_number = 2;

  int step = datasize / core_number + 1;

#pragma omp parallel for schedule(dynamic)
  for (int i = core_number - 1; i >= 0; i--)
  {
    solve(data, width, i * step);
  }

  return 0;
}

编译:

我正在使用以下命令编译代码:


g++ -Wall -g -Wextra -fsanitize=thread -pedantic -std=c++20 -O3 -m64 -fopenmp main.cpp

问题详情:

尽管使用互斥体 (

solveMutex
) 来保护关键部分,但我始终收到与数据争用相关的 ThreadSanitizer 警告。这些警告特别指向内存释放函数,例如
operator delete

我尝试过的:

  • 我尝试使用
    std::lock_guard<std::mutex>
    保护关键部分。
  • 检查互斥锁的使用和放置是否正确。

环境:

  • 编译器:g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0

如果您能了解这些数据争用警告为何持续存在以及如何有效解决这些问题,我将不胜感激。此外,任何有关改进整体设计或处理内存的建议都是有价值的。

==================
WARNING: ThreadSanitizer: data race (pid=25822)
  Write of size 8 at 0x7b0800000060 by main thread:
    #0 operator delete(void*, unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:150 (libtsan.so.0+0x8e878)
    #1 __gnu_cxx::new_allocator<double>::deallocate(double*, unsigned long) /usr/include/c++/11/ext/new_allocator.h:145 (a.out+0x484c)
    #2 std::allocator<double>::deallocate(double*, unsigned long) /usr/include/c++/11/bits/allocator.h:199 (a.out+0x484c)
    #3 std::allocator_traits<std::allocator<double> >::deallocate(std::allocator<double>&, double*, unsigned long) /usr/include/c++/11/bits/alloc_traits.h:496 (a.out+0x484c)
    #4 std::_Vector_base<double, std::allocator<double> >::_M_deallocate(double*, unsigned long) /usr/include/c++/11/bits/stl_vector.h:354 (a.out+0x484c)
    #5 std::_Vector_base<double, std::allocator<double> >::~_Vector_base() /usr/include/c++/11/bits/stl_vector.h:335 (a.out+0x484c)
    #6 std::vector<double, std::allocator<double> >::~vector() /usr/include/c++/11/bits/stl_vector.h:683 (a.out+0x484c)
    #7 void std::destroy_at<std::vector<double, std::allocator<double> > >(std::vector<double, std::allocator<double> >*) /usr/include/c++/11/bits/stl_construct.h:88 (a.out+0x484c)
    #8 void std::_Destroy<std::vector<double, std::allocator<double> > >(std::vector<double, std::allocator<double> >*) /usr/include/c++/11/bits/stl_construct.h:149 (a.out+0x484c)
    #9 void std::_Destroy_aux<false>::__destroy<std::vector<double, std::allocator<double> >*>(std::vector<double, std::allocator<double> >*, std::vector<double, std::allocator<double> >*) /usr/include/c++/11/bits/stl_construct.h:163 (a.out+0x484c)
    #10 void std::_Destroy<std::vector<double, std::allocator<double> >*>(std::vector<double, std::allocator<double> >*, std::vector<double, std::allocator<double> >*) /usr/include/c++/11/bits/stl_construct.h:196 (a.out+0x484c)
    #11 void std::_Destroy<std::vector<double, std::allocator<double> >*, std::vector<double, std::allocator<double> > >(std::vector<double, std::allocator<double> >*, std::vector<double, std::allocator<double> >*, std::allocator<std::vector<double, std::allocator<double> > >&) /usr/include/c++/11/bits/alloc_traits.h:848 (a.out+0x484c)
    #12 std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::~vector() /usr/include/c++/11/bits/stl_vector.h:680 (a.out+0x484c)
    #13 main /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:90 (a.out+0x2c79)

  Previous read of size 8 at 0x7b0800000060 by thread T5 (mutexes: write M11):
    #0 solve(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, unsigned long, unsigned long) /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:56 (a.out+0x310b)
    #1 main._omp_fn.0 /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:86 (a.out+0x329d)
    #2 <null> <null> (libgomp.so.1+0x1dc0d)

  Mutex M11 (0x55bd20bbf160) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749 (a.out+0x30cf)
    #2 std::mutex::lock() /usr/include/c++/11/bits/std_mutex.h:100 (a.out+0x30cf)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/11/bits/std_mutex.h:229 (a.out+0x30cf)
    #4 solve(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, unsigned long, unsigned long) /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:53 (a.out+0x30cf)
    #5 main._omp_fn.0 /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:86 (a.out+0x329d)
    #6 <null> <null> (libgomp.so.1+0x1dc0d)

  Thread T5 (tid=25828, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 <null> <null> (libgomp.so.1+0x1e25f)
    #2 __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 (libc.so.6+0x29d8f)

SUMMARY: ThreadSanitizer: data race ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:150 in operator delete(void*, unsigned long)
==================
==================
WARNING: ThreadSanitizer: data race (pid=25822)
  Write of size 8 at 0x7b3000000000 by main thread:
    #0 operator delete(void*, unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:150 (libtsan.so.0+0x8e878)
    #1 __gnu_cxx::new_allocator<std::vector<double, std::allocator<double> > >::deallocate(std::vector<double, std::allocator<double> >*, unsigned long) /usr/include/c++/11/ext/new_allocator.h:145 (a.out+0x487a)
    #2 std::allocator<std::vector<double, std::allocator<double> > >::deallocate(std::vector<double, std::allocator<double> >*, unsigned long) /usr/include/c++/11/bits/allocator.h:199 (a.out+0x487a)
    #3 std::allocator_traits<std::allocator<std::vector<double, std::allocator<double> > > >::deallocate(std::allocator<std::vector<double, std::allocator<double> > >&, std::vector<double, std::allocator<double> >*, unsigned long) /usr/include/c++/11/bits/alloc_traits.h:496 (a.out+0x487a)
    #4 std::_Vector_base<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::_M_deallocate(std::vector<double, std::allocator<double> >*, unsigned long) /usr/include/c++/11/bits/stl_vector.h:354 (a.out+0x487a)
    #5 std::_Vector_base<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::~_Vector_base() /usr/include/c++/11/bits/stl_vector.h:335 (a.out+0x487a)
    #6 std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::~vector() /usr/include/c++/11/bits/stl_vector.h:683 (a.out+0x487a)
    #7 main /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:90 (a.out+0x2c79)

  Previous read of size 8 at 0x7b3000000000 by thread T5 (mutexes: write M11):
    #0 std::vector<double, std::allocator<double> >::operator[](unsigned long) /usr/include/c++/11/bits/stl_vector.h:1046 (a.out+0x30f6)
    #1 solve(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, unsigned long, unsigned long) /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:56 (a.out+0x30f6)
    #2 main._omp_fn.0 /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:86 (a.out+0x329d)
    #3 <null> <null> (libgomp.so.1+0x1dc0d)

  Mutex M11 (0x55bd20bbf160) created at:
    #0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
    #1 __gthread_mutex_lock /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749 (a.out+0x30cf)
    #2 std::mutex::lock() /usr/include/c++/11/bits/std_mutex.h:100 (a.out+0x30cf)
    #3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/include/c++/11/bits/std_mutex.h:229 (a.out+0x30cf)
    #4 solve(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, unsigned long, unsigned long) /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:53 (a.out+0x30cf)
    #5 main._omp_fn.0 /home/walid/Desktop/minimise/build sanitize/1_________decl.cpp:86 (a.out+0x329d)
    #6 <null> <null> (libgomp.so.1+0x1dc0d)

  Thread T5 (tid=25828, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 <null> <null> (libgomp.so.1+0x1e25f)
    #2 __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 (libc.so.6+0x29d8f)

SUMMARY: ThreadSanitizer: data race ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:150 in operator delete(void*, unsigned long)
==================
ThreadSanitizer: reported 2 warnings

c++ openmp mutex race-condition thread-sanitizer
1个回答
0
投票

我最近也遇到这个问题了。经过我的搜索,我发现需要使用 TSAN 构建 OpenMP 运行时库 我可以对 OpenMP 程序使用 Thread Sanitizer 吗? 以及 clang 的 Thread Sanitizer 是否报告误报?。希望这可以解决您的问题。祝你有美好的一天:D

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