gpt4 book ai didi

c++ - curl 在线程调用中崩溃

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:08:36 25 4
gpt4 key购买 nike

如果 curl 是线程安全的,我会阅读 SO 文章。这个非常简单的代码崩溃了——并非总是如此,但是当我连续多次调用该程序时[非并行],它会因段错误或以下错误而崩溃。

到目前为止,我确信我遵循文档中所述的关于 curl 和线程的规则。

在测试中我发现它在 curl_easy_perform() 中崩溃了。

#include <curl/curl.h>
#include <stdio.h>
#include <thread>

class curlClass
{
private:
CURL * curl {};
CURLcode res;
const char * sUrl;

public:
auto loadDataFromUrl() -> void;
static auto initCurl() -> void;
static auto releaseCurl() -> void;
static auto callbackSaveData( void * content, size_t size, size_t nmemb, curlClass * classInstance ) -> size_t;
curlClass( const char * );
~curlClass();
};

auto curlClass::initCurl() -> void
{
curl_global_init(CURL_GLOBAL_SSL);
}

auto curlClass::releaseCurl() -> void
{
curl_global_cleanup();
}

curlClass::curlClass( const char * sUrl ) : sUrl( sUrl )
{
curl = curl_easy_init();
}

curlClass::~curlClass()
{
curl_easy_cleanup( curl );
}

auto curlClass::callbackSaveData( __attribute__ ((unused)) void *contents,
size_t size,
size_t nmemb,
__attribute__ ((unused)) curlClass * classInstance
) -> size_t
{
return size * nmemb;
}

auto curlClass::loadDataFromUrl() -> void
{
if ( curl )
{
curl_easy_setopt(curl, (CURLoption) CURLOPT_SSL_VERIFYPEER, nullptr);
curl_easy_setopt(curl, (CURLoption) CURLOPT_URL, sUrl);
curl_easy_setopt(curl, (CURLoption) CURLOPT_WRITEFUNCTION, callbackSaveData);
res = curl_easy_perform(curl);
printf( "Return: %d\n", res );
}
}

auto worker( const char * sUrl ) -> void
{
curlClass myInstance( sUrl );
myInstance.loadDataFromUrl();
}

int main(void)
{
curl_version_info_data * curl_version = curl_version_info(CURLVERSION_NOW);

printf( "Curl version=%s\n", curl_version->version );
curlClass::initCurl();

std::thread thread1( worker, "https://www.google.com");
std::thread thread2( worker, "https://www.google.com" );
std::thread thread3( worker, "https://www.google.com" );
std::thread thread4( worker, "https://www.google.com" );
std::thread thread5( worker, "https://www.google.com" );
std::thread thread6( worker, "https://www.google.com" );
std::thread thread7( worker, "https://www.google.com" );

thread1.join();
thread2.join();
thread3.join();
thread4.join();
thread5.join();
thread6.join();
thread7.join();

curlClass::releaseCurl();
}

更新:

我编译了新的 curl 版本 7.46.0。这是可能的错误转储之一:

Curl version=7.46.0
*** glibc detected *** ./curl_crash: double free or corruption (out): 0x00007fcd200056d0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x76618)[0x7fcd2ff4a618]
/lib64/libc.so.6(cfree+0x6c)[0x7fcd2ff4f65c]
/usr/lib64/libcrypto.so.0.9.8(CRYPTO_free+0x19)[0x7fcd2f9f13f9]
/usr/lib64/libcrypto.so.0.9.8(+0xf407d)[0x7fcd2f9d307d]
/usr/lib64/libcrypto.so.0.9.8(ERR_clear_error+0xd)[0x7fcd2f9efd1d]
/usr/local/lib/libcurl.so.4(+0x4849c)[0x7fcd30a2d49c]
/usr/local/lib/libcurl.so.4(+0x4b970)[0x7fcd30a30970]
/usr/local/lib/libcurl.so.4(+0x1073d)[0x7fcd309f573d]
/usr/local/lib/libcurl.so.4(+0x20451)[0x7fcd30a05451]
/usr/local/lib/libcurl.so.4(+0x31e0e)[0x7fcd30a16e0e]
/usr/local/lib/libcurl.so.4(curl_multi_perform+0xdd)[0x7fcd30a1780d]
/usr/local/lib/libcurl.so.4(curl_easy_perform+0x10b)[0x7fcd30a1001b]
./curl_crash(_ZN9curlClass15loadDataFromUrlEv+0x88)[0x408002]
./curl_crash(_Z6workerPKc+0x2c)[0x408051]
./curl_crash(_ZNSt12_Bind_simpleIFPFvPKcES1_EE9_M_invokeIILm0EEEEvSt12_Index_tupleIIXspT_EEE+0x40)[0x409818]
./curl_crash(_ZNSt12_Bind_simpleIFPFvPKcES1_EEclEv+0x1d)[0x409711]
./curl_crash(_ZNSt6thread5_ImplISt12_Bind_simpleIFPFvPKcES3_EEE6_M_runEv+0x1c)[0x40968e]
/usr/local/lib64/libstdc++.so.6(+0xb5c10)[0x7fcd30790c10]
/lib64/libpthread.so.0(+0x77f6)[0x7fcd2e81c7f6]
/lib64/libc.so.6(clone+0x6d)[0x7fcd2ffaf09d]
======= Memory map: ========

我真的不知道哪里出了问题。当我启动该程序 5 次时,至少有一次它崩溃了。

我做错了什么,或者根据转储,我有可能使用旧的 SSL 库吗?

编译命令行:

g++ --std=c++11 -Wall -Werror -pedantic -Wextra curl_crash.cpp -o curl_crash -lcurl -rdynamic && ./curl_crash

最佳答案

我过早地停止阅读 SSL 库文档。感谢 Petesh,他在访问 openssl 时指出了这个问题,我可以快速解决这个问题。

curl 文档中所述 Thread-safe --> TLS --> OpenSSL 我必须使用这些函数。我将其改编为 C++11 标准:

#include <mutex>
#include <openssl/err.h>
#include <vector>

class SslCurlWrapper
{
private:
static std::vector<std::mutex> vectorOfSslMutex;
static auto id_function() -> unsigned long { return ( pthread_self() ); }
static auto locking_function(int, int, const char *, int) -> void;

public:
SslCurlWrapper();
~SslCurlWrapper();
};

std::vector<std::mutex> SslCurlWrapper::vectorOfSslMutex( CRYPTO_num_locks() );

//----------------------------------------
auto SslCurlWrapper::locking_function( int mode,
int n,
__attribute__ ((unused)) const char * file,
__attribute__ ((unused)) int line
) -> void
//----------------------------------------
{
if ( mode & CRYPTO_LOCK ) vectorOfSslMutex [n].lock();
else vectorOfSslMutex [n].unlock();
}

//------------------------------
SslCurlWrapper::SslCurlWrapper()
//------------------------------
{
CRYPTO_set_id_callback( id_function );
CRYPTO_set_locking_callback( locking_function );
}

//-------------------------------
SslCurlWrapper::~SslCurlWrapper()
//-------------------------------
{
CRYPTO_set_id_callback( nullptr );
CRYPTO_set_locking_callback( nullptr );
}

然后可以这样使用:

int main(void)
{
SslCurlWrapper sslObject; // hook is set up
// here it is safe to use the curl library in a multi-thread-environment
} // hook is released/uninstalled

编译命令:

g++ -std=c++11 -Wall -Werror -Wextra -pedantic -c SslCurlWrapper.cpp

必须将 -lcrypto 库添加到编译器命令行,以便链接器不会报错。

我个人的看法是,我有点惊讶 openssl 库中的默认模式没有实现上述两个功能,以避免每个程序员都必须从头开始。这可能是最低限度的实现...

测试 shell 脚本调用程序 200 次,没有任何崩溃。在它立即崩溃之前。对我来说它是固定的。

我不明白 SergeyA 的无用评论。

关于c++ - curl 在线程调用中崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34998440/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com