I tried this:
//----------------------------------------------------------------------------
struct H5DReadArray
{
template <typename ArrayType>
void operator()(ArrayType* array, hid_t arrayId, hid_t memType, bool& success)
{
success = H5Dread(arrayId, memType, H5S_ALL, H5S_ALL, H5P_DEFAULT, array->GetPointer(0)) >= 0;
}
};
//----------------------------------------------------------------------------
std::vector<vtkSmartPointer<vtkDataArray>> ReadArrays(vtkSR3Reader* reader, hid_t fileId,
const std::vector<std::string>& arraysToRead,
const std::map<std::string, std::string>& acronymToName)
{
std::vector<vtkSmartPointer<vtkDataArray>> arrays(arraysToRead.size(), nullptr);
auto readArrays = [&](vtkIdType begin, vtkIdType end)
{
for (vtkIdType i = begin; i < end; ++i)
{
const auto& path = arraysToRead[i];
// Open the dataset
vtkHDF::ScopedH5DHandle arrayId = H5Dopen(fileId, path.c_str());
if (arrayId < 0)
{
vtkErrorWithObjectMacro(reader, "Could not open array at path: " << path);
return;
}
// Get its dataspace and ensure 1D
vtkHDF::ScopedH5SHandle arraySpace = H5Dget_space(arrayId);
if (H5Sget_simple_extent_ndims(arraySpace) != 1)
{
vtkErrorWithObjectMacro(reader, "Array is not 1D: " << path);
return;
}
// Get its length
hsize_t length = 0;
H5Sget_simple_extent_dims(arraySpace, &length, nullptr);
if (length == 0)
{
vtkErrorWithObjectMacro(reader, "Dataset has zero length: " << path);
return;
}
// What is its file datatype?
vtkHDF::ScopedH5THandle arrayDataType = H5Dget_type(arrayId);
vtkHDF::ScopedH5THandle memType = H5Tget_native_type(arrayDataType, H5T_DIR_DEFAULT);
H5T_class_t cls = H5Tget_class(arrayDataType);
// Choose a VTK array and HDF5 memory type
vtkSmartPointer<vtkDataArray> arr;
if (cls == H5T_INTEGER || cls == H5T_FLOAT)
{
if (H5Tequal(memType, H5T_NATIVE_CHAR))
{
arr = vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_CHAR));
}
else if (H5Tequal(memType, H5T_NATIVE_SCHAR))
{
arr = vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_SIGNED_CHAR));
}
else if (H5Tequal(memType, H5T_NATIVE_UCHAR))
{
arr =
vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_UNSIGNED_CHAR));
}
else if (H5Tequal(memType, H5T_NATIVE_SHORT))
{
arr = vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_SHORT));
}
else if (H5Tequal(memType, H5T_NATIVE_USHORT))
{
arr =
vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_UNSIGNED_SHORT));
}
else if (H5Tequal(memType, H5T_NATIVE_INT))
{
arr = vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_INT));
}
else if (H5Tequal(memType, H5T_NATIVE_UINT))
{
arr =
vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_UNSIGNED_INT));
}
else if (H5Tequal(memType, H5T_NATIVE_LONG))
{
arr = vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_LONG));
}
else if (H5Tequal(memType, H5T_NATIVE_ULONG))
{
arr =
vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_UNSIGNED_LONG));
}
else if (H5Tequal(memType, H5T_NATIVE_LLONG))
{
arr = vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_LONG_LONG));
}
else if (H5Tequal(memType, H5T_NATIVE_ULLONG))
{
arr = vtkSmartPointer<vtkDataArray>::Take(
vtkDataArray::CreateDataArray(VTK_UNSIGNED_LONG_LONG));
}
else if (H5Tequal(memType, H5T_NATIVE_FLOAT))
{
arr = vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_FLOAT));
}
else if (H5Tequal(memType, H5T_NATIVE_DOUBLE))
{
arr = vtkSmartPointer<vtkDataArray>::Take(vtkDataArray::CreateDataArray(VTK_DOUBLE));
}
else
{
vtkErrorWithObjectMacro(reader, "Unsupported data type for dataset " << path);
return;
}
}
else
{
vtkErrorWithObjectMacro(
reader, "Unsupported class type " << cls << " for dataset " << path);
return;
}
// Name the array: use acronymToName if we have a mapping for the leaf name
const std::string acronym = vtksys::SystemTools::GetFilenameName(path);
const auto& name = acronymToName.at(acronym);
arr->SetName(name.c_str());
// Allocate and read
int numComponents = 1;
if (acronym == "BLOCKSIZE" || acronym == "NODES")
{
numComponents = 3;
}
arr->SetNumberOfComponents(numComponents);
arr->SetNumberOfTuples(static_cast<vtkIdType>(length / numComponents));
bool success;
if (!vtkArrayDispatch::Dispatch::Execute(arr, H5DReadArray{}, arrayId, memType, success) ||
!success)
{
vtkErrorWithObjectMacro(reader, "Failed to read dataset " << path << ": " << acronym);
return;
}
arrays[i] = arr;
}
};
readArrays(0, static_cast<vtkIdType>(arrays.size()));
// vtkSMPTools::For(0, static_cast<vtkIdType>(arrays.size()), readArrays);
const bool success =
std::all_of(arrays.begin(), arrays.end(), [](const auto& array) { return array != nullptr; });
return success ? arrays : std::vector<vtkSmartPointer<vtkDataArray>>{};
}
When i enable // vtkSMPTools::For(0, static_cast(arrays.size()), readArrays); which does the multithreading. hdf5 segfaults in 10 different places.
I tried creating a different file id for each thread, and it still failed, even when i had a mutex in all places except the H5Dread.
It feels like there is a global state that only 1 thread can modify at a time. If you have any example that successfully multithreads the reading of an hdf5 array, i would be more than happy to take a look, cause google/chatgpt were not of any help so far.