在读取大文件时杀死std::thread
Kill std::thread while reading a big file
我有一个std::thread
函数,它调用fopen
将一个大文件加载到数组中:
void loadfile(char *fname, char *fbuffer, long fsize)
{
FILE *fp = fopen(fname, "rb");
fread(fbuffer, 1, fsize, fp);
flose(fp);
}
这是由调用的
std::thread loader(loadfile, fname, fbuffer, fsize);
loader.detach();
在某个时刻,我的程序中有东西想要停止读取该文件,并要求另一个文件。问题是,当我删除fbuffer
指针时,loader
线程仍在运行,并且我得到了一个消除异常的竞赛条件。
我怎样才能弄死那根线?我的想法是检查fbuffer
的存在,并可能将fread
分成小块:
void loadfile(char *fname, char *fbuffer, long fsize)
{
FILE *fp = fopen(fname, "rb");
long ch = 0;
while (ch += 256 < fsize)
{
if (fbuffer == NULL) return;
fread(fbuffer + ch, 1, 256, fp);
}
fclose(fp);
}
这会减慢文件的读取速度吗?你有更好的主意吗?
您应该避免不惜一切代价杀死线程。这样做会导致邪恶的事情发生,比如资源被永久锁定。
必须为线程提供一个对标志的引用,该标志的值可以从其他地方设置,以告诉线程自愿退出。
您不能将缓冲区用于此目的;如果一个线程在另一个线程写入缓冲区时删除了缓冲区的内存,那么就会发生非常糟糕的事情。(内存损坏。)所以,传递一个对布尔标志的引用。
当然,为了让线程能够定期检查标志,它必须有小块的工作要做,所以将fread
划分为小块是个好主意。
256字节可能有点太小了;肯定使用4k或更多,甚至64k。
通常不会杀死线程-这样做可能会导致资源泄漏、无法退出的关键部分以及程序状态不一致。
你的想法几乎是准确的,但你需要一种方式来通知线程完成。您可以使用线程和线程在每次读取后读取的其余代码之间共享的布尔值,一旦设置了布尔值,停止读取缓冲区,清理文件句柄并干净退出。
另一方面,在现代C++中,大多数时候都不赞成自己处理具有所属语义的指针的删除——除非你有充分的理由不这样做,否则我建议使用stl-fstream和字符串类。
您需要正确的线程同步。关于资源泄漏的评论和@Mike Nakis关于通过设置布尔值自愿退出线程的建议几乎是正确的(嗯,它们是正确的,但不完整)。你需要走得更远。
您不仅必须确保加载程序线程自行退出,还必须确保它在删除要写入的缓冲区之前已经退出。或者,至少,您必须确保它在您删除缓冲区后不会以任何方式接触该缓冲区。检查指针是否为null无效有两个原因。首先,它无论如何都不起作用,因为您正在查看原始指针的副本(您必须使用指针指针或引用)。其次,更重要的是,即使检查有效,if
语句和fread
之间也存在竞争条件。换句话说,无法保证在fread
访问缓冲区时不会释放缓冲区(无论块有多小)。
至少,您需要两个布尔标志,但最好使用适当的同步原语(如条件变量)来通知主线程(这样您就不必旋转等待加载程序退出,但可以阻止)。
正确的操作方式是:
- 通知加载程序线程
- 等待加载程序线程向我发出信号(cond-var上的块)
- Loader线程接收通知,设置条件变量,之后再也不接触缓冲区,然后退出
- 恢复(删除缓冲区、分配新缓冲区等)
如果你不坚持分离加载程序线程,你可以在告诉它退出后简单地join
它(所以你不需要第二个var)。
- 在std::thread中,joinable()然后join()线程安全吗
- 分离一个静态常量 std::thread?
- 当指向对象的指针作为参数传递给 std::thread 时,内存可见性
- 如何从 std::thread 返回值
- 将 std::thread by 值推送到列表中
- 转发变量参数列表以模拟 std::thread
- 对 'std::thread::_M_start_thread CMake 的未定义引用进行基准测试
- std::thread 增加 DLL 引用计数,从而防止卸载 DLL
- 如何防止 std::thread 在 QT 中冻结 GUI?
- 对带有唯一指针的 std::thread 使用类成员函数时出现编译错误
- 为什么参数在构造 std::thread 时移动两次
- std::thread::_Invoker 使用线程编程时出错
- 在线程 A 中创建一个 std::thread 对象,在线程 B 中连接
- 为什么编译器抱怨 std::thread 参数在转换为右值后必须是可调用的?
- ZeroMQ 在使用 std::thread 创建工作线程时崩溃
- 在没有复制构造函数的对象的成员函数中启动 std::thread
- CLang:在 std::thread 中运行函数会导致结构创建BAD_ACCESS
- 调用以CWinThread为基的类运算符()的std::thread失败
- 如何通过std::thread生成多个线程
- std::future::get()或std::future::wait()是std::thread::join()的替