【发布时间】:2016-07-18 10:01:45
【问题描述】:
我有一个关于使用 HDF5 线程安全库的问题。
我目前使用的一个 HDF5 C++ 库(静态)实例是由我的一位同事使用"HDF5_ENABLE_PARALLEL" 或"HDF5_ENABLE_THREADSAFE" 选项编译的。
我尝试做的是使用多个线程访问包含一些数据的 HDF 文件。数据的实际读取不需要并行。
我的代码目前看起来有点像这样简化:
// includes etc.
int main() {
H5File t_file(FILENAME, H5F_ACC_RDONLY);
thread t1(read_row, cref(t_file), 0);
thread t2(read_row, cref(t_file), 1);
t1.join();
t2.join();
return 0;
}
void read_row(const H5File & p_file, size_t p_row){
double data[DIM_Y][DIM_X];
try {
DataSet t_dataset = p_file.openDataSet("/Group0/Set0");
DataSpace t_dataspace = t_dataset.getSpace();
hsize_t dims[2];
auto status = t_dataspace.getSimpleExtentDims(dims, nullptr);
hsize_t count[2] = { 1, DIM_X };
hsize_t offset[2] = { p_row, 0 };
t_dataspace.selectHyperslab(H5S_SELECT_SET, count, offset);
hsize_t mem_dim[2] = { 1, DIM_X };
DataSpace t_memspace(RANK, mem_dim);
hsize_t mem_offset[2] = { 0, 0 };
t_memspace.selectHyperslab(H5S_SELECT_SET, count, mem_offset);
t_dataset.read(data, PredType::NATIVE_DOUBLE, t_memspace, t_dataspace);
}
catch (...){
cout << "Caught some exception" << endl;
}
}
代码可以编译,如果我大部分时间都运行该程序,一切都会顺利。
但是有时我会收到以下错误消息:
HDF5-DIAG: Error detected in HDF5 (1.8.16) thread 0:
#000: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5D.c line 358 in H5Dopen2(): not found
major: Dataset
minor: Object not found
#001: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5Gloc.c line 430 in H5G_loc_find(): can't find object
major: Symbol table
minor: Object not found
#002: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5Gtraverse.c line 861 in H5G_traverse(): internal path traversal failed
major: Symbol table
minor: Object not found
#003: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5Gtraverse.c line 596 in H5G_traverse_real(): can't look up component
major: Symbol table
minor: Object not found
#004: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5Gobj.c line 1139 in H5G__obj_lookup(): can't check for link info message
major: Symbol table
minor: Can't get value
#005: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5Gobj.c line 333 in H5G__obj_get_linfo(): unable to read object header
major: Symbol table
minor: Can't get value
#006: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5Omessage.c line 896 in H5O_msg_exists(): unable to release object header
major: Object header
minor: Unable to unprotect metadata
#007: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5O.c line 1963 in H5O_unprotect(): unable to release object header
major: Object header
minor: Unable to unprotect metadata
#008: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5Gobj.c line 1524 in H5O_msg_exists(): H5G__obj_get_linfo
major: Object cache
minor: Unable to unprotect metadata
#009: D:\Projects\CANoe\90\CMake-hdf5-1.8.16\hdf5-1.8.16\src\H5C.c line 5281 in H5C_unprotect(): Entry already unprotected??
major: Object cache
minor: Unable to unprotect metadata
我怀疑这是因为库本身在当前形式下不是线程安全的。
我现在的问题是:
如果我使用 --enable-threadsafe 选项重新编译库,那么我是否能够像上面那样使用 HDF5 文件。
库本身应该确保一次只有一个线程在访问文件(或正在执行 API 调用)对吗?
如果我重新编译这个库,我还能使用 C++ API 吗?
我也尝试使用互斥锁锁定 API 调用,但仍然遇到一些问题。
如果有人能回答我的问题,我将不胜感激。 我希望我对自己的解释足够好。对不起,如果这有点长;)。
提前致谢。
【问题讨论】:
-
你需要修改那个文件吗?如果没有,您可以尝试在每个线程中打开文件,即将
H5File t_file(FILENAME, H5F_ACC_RDONLY);移动到read_row()。 -
无论如何,依赖
--enable-threadsafe配置选项可能很危险。它实际上是什么意思?它将在 HDF5 库源代码中启用一些锁定机制。但是这种锁定机制依赖于特定的线程队列。表面上看,它是 Pthreads 库,但您使用的是 C++11 线程(也可能是基于 Pthreads 构建的)。不同线程范式的混合非常脆弱,一般不推荐。同理,不建议 HDF5 与 OpenMP 一起使用。 -
@DanielLangr 不,我不会修改文件,因此将 H5File 对象移动到线程可能是一个解决方案。我在上面的例子中试过这个,到目前为止它似乎可以工作。可悲的是,早些时候的崩溃发生得非常不可预测,所以我不太确定。但我想我可能会以这种方式使用图书馆。只有一个包装器是线程安全的并且执行实际的 IO。而且这个包装器可以被多个工作线程使用。我认为这可能有效。感谢您的回复。
标签: c++ thread-safety hdf5 hdf