2011-01-16 26 views
0

私はCURLのスレッドURLを束ねて、並列にダウンロードするC++のアプリケーションを開発中です。マルチスレッドカールアプリケーションにメモリ割り当ての問題があります

私は画像や動画などをダウンロードするのに安全な方法を採用しています。データが文字列か文字配列であると仮定するのではなく、memcpyを使用します。

私は、各スレッドにいくつかの事柄について構造体thread_statusを渡します。この構造により、親プロセスはスレッドのダウンロードが完了したことを知ることができます。また、cURLが書き込み用のバッファをさらに返すので、cURLがダウンロードしているデータを格納し、そのサイズを追跡します。

私は、ダウンロード時に各スレッドに初期化時に割り当てられた各構造体を指すポインタ(void *)を渡します。最初のページが正しくダウンロードされた後、私はrealloc()からエラーを取得し続けます。

ここに私の問題を説明する最も単純な例があります。このサンプルはマルチスレッドではありませんが、同様の構造を使用してそれ自体を追跡します。

#include <string> 
#include <assert.h> 
#include <iostream> 
#include <curl/curl.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

#define NOT_READY 1 
#define READY  0 

using namespace std; 

struct thread_status { 
    int id; 
    pthread_t *pid; 
    int readyState; 
    char *url; 
    void *data; 
    size_t bufferlen; 
    size_t writepos; 
    int initialized; 
} ; 


size_t static 
writefunction( void *ptr, size_t size, 
        size_t nmemb, void *userdata) 
{ 
    size_t nbytes = size*nmemb; 
     struct thread_status **this_status; 
     this_status = (struct thread_status **) userdata; 

     if (!(*this_status)->initialized){ 
       (*this_status)->data = (void *)malloc(1024); 
       (*this_status)->bufferlen = 1024; 
       (*this_status)->writepos = 0; 
       (*this_status)->initialized = true; 
     } 

     if ((*this_status)->bufferlen < ((*this_status)->writepos + nbytes)){ 
      (*this_status)->bufferlen = (*this_status)->bufferlen + nbytes; 
      (*this_status)->data = realloc((*this_status)->data, (size_t) ((*this_status)->writepos + nbytes)); 
     } 

     assert((*this_status)->data != NULL); 
     memcpy((*this_status)->data + (*this_status)->writepos, ptr, nbytes); 
     (*this_status)->writepos += nbytes; 
    return nbytes; 
} 

void *pull_data (void *my_struct){ 

struct thread_status *this_struct; 
this_struct = (struct thread_status *) my_struct; 
this_struct->initialized = false; 

cout<<(char *)this_struct->url<<"\n"; 

CURL *curl; 
curl = curl_easy_init(); 
size_t rc = 0; 

while(true){ 

    curl_easy_setopt(curl, 
     CURLOPT_WRITEFUNCTION, writefunction); 
    curl_easy_setopt(curl, 
     CURLOPT_WRITEDATA, (void *) &this_struct); 
    curl_easy_setopt(curl, 
     CURLOPT_NOSIGNAL, true); 
    curl_easy_setopt(curl, 
     CURLOPT_URL, (char *)this_struct->url); 

    if (curl_easy_perform(curl) != 0){ 
     cout<<"curl did not perform\n"; 
     exit(1); 
    } else { 
    if (this_struct->data != NULL){ 
      // Use a binary write. 
      rc = fwrite(this_struct->data, this_struct->writepos, 1, stdout); 
      free(this_struct->data); 
     } else { 
      cout<<"Data is NULL\n"; 
     } 
    } 

    // Tell the babysitter the thread is ready. 
    this_struct->readyState = READY; 
// This would pause the thread until the parent thread has processed the data in it. 
// while(this_struct->readyState == READY){;} 

    // Now get ready for another round! 
    this_struct->writepos = (size_t) 0; 
    this_struct->initialized = false; 
    this_struct->bufferlen = (size_t) 0; 

    break; 
} 

    curl_easy_cleanup(curl); 
    return (void *)"a"; 
} 

int main(){ 

    char *urls[] = { "http://www.example.com/", "http://www.google.com", "http://www.touspassagers.com/", "http://www.facebook.com/" }; 
    int i=0; 
    struct thread_status mystatuses[4]; 
    for (i=0;i<4;i++){ 

     struct thread_status my_status; 
     char *data; 

     my_status.id = i; 
     my_status.readyState = NOT_READY; 
     my_status.url = urls[i]; 
     my_status.data = data; 
     my_status.bufferlen = 0; 
     my_status.writepos = 0; 
     my_status.initialized = false; 

     mystatuses[i] = my_status; 
    } 

    for (i=0;i<4;i++){ 
     cout<<"pulling #"<<i<<"\n"; 
     pull_data((void *)&mystatuses[i]); 
    } 

} 

誰かが私のエラーの原因や救済策について教えていただけたら、私はそれを感謝します。

+1

パフォーマンスヒント:現在の割り当て方法では、大容量ファイルの処理が非常に遅く、メモリの断片化が多く発生するO(n^2)の処理が実行されます。スペースを使い果たすたびにバッファのサイズを2倍にすると、割り当てられた領域の50%以上を無駄にすることなく、O(n)の作業だけを行います。 –

+0

素晴らしい!ヒントはありがとう: – KeatsKelleher

答えて

1

明らかに1KBは、最初のcURLバッファを処理するのに十分なメモリではありません。私は1024バイトをnバイトに変更しました。

バッファ内に置かれたメモリmemcpyは、割り当てられたメモリ上で実行されたため、破損していました。

誰でも完全な実装を見て気にならば、私はそれについてのポストをした: http://www.touspassagers.com/2011/01/a-working-curlopt_writefunction-function-for-libcurl/

+0

ここであなた自身の答えを受け入れる必要があります。 –

+0

するでしょう...ちょうど2日待たなければなりません。 – KeatsKelleher

3

あなたは、メモリの問題の原因を見つけやすくするためにvalgrindを使用して検討するかもしれません。

+0

I <3 valgrind。ハハ。はい。 +1 – KeatsKelleher

関連する問題