curl在线程调用中崩溃

时间:2016-01-25 17:21:11

标签: c++ multithreading curl

如果- pear: name=Net_URL2 state=latest 是线程安全的,我会阅读SO文章。这个非常简单的代码崩溃 - 并不总是,但是当我连续多次调用程序[不平行]时,它会因分段错误或以下错误而崩溃。

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

在测试中,我发现它在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

我真的不知道出了什么问题。当我启动程序5次,然后至少崩溃一次。

我做错了什么或者是否可能 - 根据转储 - 我使用旧的SSL库?

要编译的命令行:

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: ========

1 个答案:

答案 0 :(得分:2)

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

curl文档Thread-safe中所述 - &gt; TLS - &gt; 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的无用评论。