在 C 中使用 libcurl 按线程读取一个文件
Read one file by thread with libcurl in C
我想用 libcurl 读取多个联机文件(尤其是使用 fopen.c 中定义的函数)。为此,我想使用多个线程,但每个文件只使用一个线程。我的代码在一个 URL 上工作正常,但会出现分段错误,或者对多个文件进行核心转储。
这是我的代码:
void * extract_file(void * filename)
{
URL_FILE *handle;
int err;
CURL *curl = curl_easy_init();
if(curl == NULL) {
fprintf(stderr, "Error while initializing libcurl.\n");
exit(EXIT_FAILURE);
}
CURLcode curlcode = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, true);
char *file = (char *) filename;
handle = url_fopen(file, "rb");
if(handle == NULL) {
fprintf(stderr, "Error while opening %s.\n", file);
exit(EXIT_FAILURE);
}
uint64_t n;
bool empty = true;
while(url_fread(&n, sizeof(uint64_t), 1, handle) != 0) {
empty = false;
sem_wait(&empty1);
pthread_mutex_lock(&mutex1);
push(&buffer1, n);
pthread_mutex_unlock(&mutex1);
sem_post(&full1);
}
err = url_fclose(handle);
if(err != 0) {
fprintf(stderr, "Error while closing %s.\n", file);
}
curl_easy_cleanup(curl);
debug_printf("Leaving extract_file.\n");
if(empty) {
fprintf(stderr, "%s is either empty or non-existing.\n", file);
exit(EXIT_FAILURE);
}
pthread_exit(NULL);
}
注意:我删除了一些不重要的代码细节。
每个 "reader" 线程使用通常的 pthread_create 启动此函数。
所以我有两个问题:
1)为什么我不能用这段代码一次读取多个在线文件而不会导致分段错误?
2) 当文件是不存在的本地文件或不存在的在线文件时,为什么 handle == NULL 条件不成立? (这就是为什么我必须使用 bool 空变量)。
另请注意,我在启动任何线程之前使用了 curl_global_init()。
提前致谢。
编辑:发生分段错误时我的 GDB 输出:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff2924700 (LWP 3280)]
0x00007ffff7684f3a in ?? () from /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4
我认为从您的代码来看,它与 curl_easy_init()
调用 curl_global_init()
有关,因为您的代码本身并没有调用它。
卷曲文档 page 说:
If you did not already call curl_global_init, curl_easy_init does it
automatically. This may be lethal in multi-threaded cases, since
curl_global_init is not thread-safe, and it may result in resource
problems because there is no corresponding cleanup.
因此,尝试在代码中 curl_easy_init()
之前调用 curl_global_init()
。
我终于找到了解决办法。
libCurl 不允许在不同的线程中使用相同的句柄(参见here, in section about thread-safety), it causes errors. So we can't use fopen.c 直接在不同线程中读取多个文件。我们必须修改全局变量multi_handle
添加__thread
, 那么它就完美了。
我想用 libcurl 读取多个联机文件(尤其是使用 fopen.c 中定义的函数)。为此,我想使用多个线程,但每个文件只使用一个线程。我的代码在一个 URL 上工作正常,但会出现分段错误,或者对多个文件进行核心转储。
这是我的代码:
void * extract_file(void * filename)
{
URL_FILE *handle;
int err;
CURL *curl = curl_easy_init();
if(curl == NULL) {
fprintf(stderr, "Error while initializing libcurl.\n");
exit(EXIT_FAILURE);
}
CURLcode curlcode = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, true);
char *file = (char *) filename;
handle = url_fopen(file, "rb");
if(handle == NULL) {
fprintf(stderr, "Error while opening %s.\n", file);
exit(EXIT_FAILURE);
}
uint64_t n;
bool empty = true;
while(url_fread(&n, sizeof(uint64_t), 1, handle) != 0) {
empty = false;
sem_wait(&empty1);
pthread_mutex_lock(&mutex1);
push(&buffer1, n);
pthread_mutex_unlock(&mutex1);
sem_post(&full1);
}
err = url_fclose(handle);
if(err != 0) {
fprintf(stderr, "Error while closing %s.\n", file);
}
curl_easy_cleanup(curl);
debug_printf("Leaving extract_file.\n");
if(empty) {
fprintf(stderr, "%s is either empty or non-existing.\n", file);
exit(EXIT_FAILURE);
}
pthread_exit(NULL);
}
注意:我删除了一些不重要的代码细节。
每个 "reader" 线程使用通常的 pthread_create 启动此函数。 所以我有两个问题: 1)为什么我不能用这段代码一次读取多个在线文件而不会导致分段错误? 2) 当文件是不存在的本地文件或不存在的在线文件时,为什么 handle == NULL 条件不成立? (这就是为什么我必须使用 bool 空变量)。
另请注意,我在启动任何线程之前使用了 curl_global_init()。
提前致谢。
编辑:发生分段错误时我的 GDB 输出:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff2924700 (LWP 3280)]
0x00007ffff7684f3a in ?? () from /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4
我认为从您的代码来看,它与 curl_easy_init()
调用 curl_global_init()
有关,因为您的代码本身并没有调用它。
卷曲文档 page 说:
If you did not already call curl_global_init, curl_easy_init does it automatically. This may be lethal in multi-threaded cases, since curl_global_init is not thread-safe, and it may result in resource problems because there is no corresponding cleanup.
因此,尝试在代码中 curl_easy_init()
之前调用 curl_global_init()
。
我终于找到了解决办法。
libCurl 不允许在不同的线程中使用相同的句柄(参见here, in section about thread-safety), it causes errors. So we can't use fopen.c 直接在不同线程中读取多个文件。我们必须修改全局变量multi_handle
添加__thread
, 那么它就完美了。