Стоит задача написания fastcgi-обработчика, который по запросу вытягивает некие данные из сети и отдает наружу. Данные необходимо получать параллельно. В среднем живет около 400-500 потоков, каждый тянет порядка 10 источников.
Проблема в том что похоже при такой конфигурации curl_multi рушит мне стек - приведенный ниже пример падает на совершенно случайных местах и случайными ошибками. Может кто-либо сталкивался с этим или хотя бы протестирует указанный код? У меня на curl 7.20 и amd64 - segfault в течении 1-5 секунд после запуска. Что самое печальное - под valgrind'ом сегфолтов нет, что очень затрудняет отладку (скорее всего тормозной valgrind не может обеспечить должный уровень concurrency потоков). Сам код:
#include <iostream>
#include <curl/curl.h>
#include <cstdlib>
#define THREADS 400
#define MULTI_COUNT 20
using namespace std;
static int writer(char *data, size_t size, size_t nmemb, std::string *buffer)
{
int result = 0;
if (buffer != NULL)
{
buffer->append(data, size * nmemb);
result = size * nmemb;
}
return result;
}
void doCURL(CURLM* multi_handle, CURL** easy_handles, std::string *memory, char** envp) {
// Query* queryParams = initQuery(envp);
for (int i = 0; i < MULTI_COUNT; i++) {
easy_handles[i]=curl_easy_init();
curl_easy_setopt(easy_handles[i],CURLOPT_URL, "http://localhost/");
curl_easy_setopt(easy_handles[i],CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(easy_handles[i],CURLOPT_TIMEOUT,15);
curl_easy_setopt(easy_handles[i],CURLOPT_WRITEDATA,&memory[i]);
curl_easy_setopt(easy_handles[i], CURLOPT_NOSIGNAL, 1);
curl_multi_add_handle(multi_handle,easy_handles[i]);
}
int still_running = 0;
while(CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &still_running));
while(still_running) {
struct timeval timeout;
int rc;
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
CURLMcode res = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
if (res) {
std::cout << "You are doomed: "<< curl_multi_strerror(res) << "\n";
}
if (maxfd != -1) {
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc) {
case -1:
break;
case 0:
default:
while(CURLM_CALL_MULTI_PERFORM ==
curl_multi_perform(multi_handle, &still_running));
break;
}
}
int run;
while (NULL != curl_multi_info_read(multi_handle,&run)) ;
}
}
static void* thread_main(void* a) {
/*static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&accept_mutex);
curl_global_init(0);
pthread_mutex_unlock(&accept_mutex);
*/
std::string* memory = new std::string[MULTI_COUNT];
CURL** easy_handles = new CURL*[MULTI_COUNT]; //создаем массив хэндлов
for (;;) {
CURLM* multi_handle = curl_multi_init();
doCURL(multi_handle, easy_handles,memory, NULL);
for (int i = 0; i < MULTI_COUNT; i++) {
memory[i].clear();
curl_multi_remove_handle(multi_handle, easy_handles[i]);
curl_easy_cleanup(easy_handles[i]);
}
curl_multi_cleanup(multi_handle);
sleep(1);
}
return NULL;
}
int main(int argc, char* const argv[] ) {
pthread_t* id = new pthread_t[THREADS];
for (int i = 1; i < THREADS; i++) {
pthread_create(&id[i], NULL, thread_main, NULL);
if (i % 50 == 0) {
std::cout <<"50 spawned"<<std::endl;
}
}
std::cout <<"ALL spawned"<<std::endl;
thread_main(0);
return 0;
}
Если у вас не сегфолтится - попробуйте убрать sleep.