使用多线程读取同一个文件失败
Failed to read the same file using multithread
我创建了 50 个线程来同时读取同一个文件,然后在每个线程中尝试将其内容写入使用不同名称创建的新文件。
该代码应该生成 50 个不同的文件。
但是我得到了意想不到的结果,它只生成了 3~5 个文件。
当所有线程读取同一个文件时,不存在竞争条件,每个线程旨在将其内容写入不同的文件。
有人可以帮助我吗?谢谢!
下面列出了我的代码,它是对 Reference
的修改
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <thread>
void copy(const char *src_path, const char *dst_path);
int main(int argc, char **argv)
{
std::vector<std::thread> vth;
char *tmp = "Copy.deb";
for (int i = 0; i < 50; ++i)
{
char src[40];
memset(src, '[=10=]', sizeof(src));
sprintf(src, "%d", i);
strcat(src, tmp);
vth.emplace_back(std::bind(copy, "Original.deb", strdup(src)));
}
for (int i = 0; i < 50; ++i)
{
vth[i].join();
}
return 0;
}
void copy(const char *src_path, const char *dst_path)
{
FILE *src, *dst;
int buffer_size = 8 * 1024;
char buffer[buffer_size];
size_t length;
src = fopen(src_path, "rb");
dst = fopen(dst_path, "wb");
while (!feof(src))
{
length = fread(buffer, 1, buffer_size, src);
fwrite(buffer, 1, length, dst);
}
fclose(src);
fclose(dst);
}
我相信你的问题是你正在将 src
(这是一个指向主线程堆栈上的局部变量的指针)传递给线程的入口函数,但是由于你的 copy()
函数运行在一个单独的线程中异步地,在 copy()
函数获得机会之前,您传递指针的 char src[40]
数组已经从主线程的堆栈中弹出(并且可能被其他数据覆盖)阅读其内容。
简单的解决方法是在堆上复制该字符串,这样您就可以保证该字符串在 copy()
函数执行并读取它之前一直有效:
vth.emplace_back(std::bind(copy, "Original.deb", strdup(src)));
... 并确保您的 copy()
函数在使用完后释放堆分配:
void copy(const char *src_path, const char *dst_path)
{
FILE *src, *dst;
int buffer_size = 8 * 1024;
char buffer[buffer_size];
size_t length;
src = fopen(src_path, "rb");
dst = fopen(dst_path, "wb");
free(dst_path); // free the string previously allocated by strdup()
[...]
请注意,您目前对 "Original.deb" 参数没有相同的问题,因为 "Original.deb" 是一个字符串文字,因此静态存储在可执行文件中,这意味着它仍然有效只要程序是 运行 —— 但是 if/when 您将代码更改为不为该参数使用字符串文字,您可能也需要为它做类似的事情。
我创建了 50 个线程来同时读取同一个文件,然后在每个线程中尝试将其内容写入使用不同名称创建的新文件。
该代码应该生成 50 个不同的文件。
但是我得到了意想不到的结果,它只生成了 3~5 个文件。
当所有线程读取同一个文件时,不存在竞争条件,每个线程旨在将其内容写入不同的文件。
有人可以帮助我吗?谢谢!
下面列出了我的代码,它是对 Reference
的修改#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <thread>
void copy(const char *src_path, const char *dst_path);
int main(int argc, char **argv)
{
std::vector<std::thread> vth;
char *tmp = "Copy.deb";
for (int i = 0; i < 50; ++i)
{
char src[40];
memset(src, '[=10=]', sizeof(src));
sprintf(src, "%d", i);
strcat(src, tmp);
vth.emplace_back(std::bind(copy, "Original.deb", strdup(src)));
}
for (int i = 0; i < 50; ++i)
{
vth[i].join();
}
return 0;
}
void copy(const char *src_path, const char *dst_path)
{
FILE *src, *dst;
int buffer_size = 8 * 1024;
char buffer[buffer_size];
size_t length;
src = fopen(src_path, "rb");
dst = fopen(dst_path, "wb");
while (!feof(src))
{
length = fread(buffer, 1, buffer_size, src);
fwrite(buffer, 1, length, dst);
}
fclose(src);
fclose(dst);
}
我相信你的问题是你正在将 src
(这是一个指向主线程堆栈上的局部变量的指针)传递给线程的入口函数,但是由于你的 copy()
函数运行在一个单独的线程中异步地,在 copy()
函数获得机会之前,您传递指针的 char src[40]
数组已经从主线程的堆栈中弹出(并且可能被其他数据覆盖)阅读其内容。
简单的解决方法是在堆上复制该字符串,这样您就可以保证该字符串在 copy()
函数执行并读取它之前一直有效:
vth.emplace_back(std::bind(copy, "Original.deb", strdup(src)));
... 并确保您的 copy()
函数在使用完后释放堆分配:
void copy(const char *src_path, const char *dst_path)
{
FILE *src, *dst;
int buffer_size = 8 * 1024;
char buffer[buffer_size];
size_t length;
src = fopen(src_path, "rb");
dst = fopen(dst_path, "wb");
free(dst_path); // free the string previously allocated by strdup()
[...]
请注意,您目前对 "Original.deb" 参数没有相同的问题,因为 "Original.deb" 是一个字符串文字,因此静态存储在可执行文件中,这意味着它仍然有效只要程序是 运行 —— 但是 if/when 您将代码更改为不为该参数使用字符串文字,您可能也需要为它做类似的事情。