URL: https://www.opennet.ru/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 9411
[ Назад ]

Исходное сообщение
"fastcgi в нескольких потоках"

Отправлено scx75 , 14-Мрт-12 12:27 
Здравствуйте.
Пишу прогу на си++. Пытаюсь обработать fastcgi запрос в нескольких потоках, принимая только одним
код примерно следующий:

while(FCGX_Accept_r(&req)==0) {
  // кладу в общую очередь объект req
  FCGX_Init_req(&req); // точно не помню названия функции
  // семафор.post();
}

в потоках делаю следующее:


while(true) {
  семафор.wait();
  // req = вынимаю из очереди
  // обрабатываю, вывожу ответ
  FCGX_Finish_r(&req); // объекты req локальные в каждом из потоков
}

тестирую совместо с nginx, и поведение неоднозначно, в основном nginx выдает 502, бывает падает с ошибками памяти
пробывал разные варианты, когда потоки "засыпали"
сейчас меня больше интересует, сможет ли меня кто нибудь проконсультировать, потому что не нашел обсуждений fastcgi на си


Содержание

Сообщения в этом обсуждении
"fastcgi в нескольких потоках"
Отправлено parad , 14-Мрт-12 13:46 
лучше бы код привел, а не на память как-то так. зае*бись вопросы пошли.

напрашиваются 3 ошибки( в порядке вероятности ):

- кладешь в очеред, непроинициализированная FCGX_InitRequest'ом структура копируется, потом ты инициализируешь стековую переменную, а в очереди остается фигня. Тобишь измени порядок вызова FCGX_InitRequest и покладки в очередь.

- фцги у тебя работает через std{in,out,err} - должен в многопоточном приложении по сокетам.

- конкурентный доступ без блокировки к очереди в многопоточном приложении.

учись задавать полные вопросы с описанием.


"fastcgi в нескольких потоках"
Отправлено scx75 , 15-Мрт-12 11:10 
> - кладешь в очеред, непроинициализированная FCGX_InitRequest'ом структура копируется,
> потом ты инициализируешь стековую переменную, а в очереди остается фигня. Тобишь
> измени порядок вызова FCGX_InitRequest и покладки в очередь.

инициализация есть
полный код http://govnokod.com/6123

> - фцги у тебя работает через std{in,out,err} - должен в многопоточном приложении
> по сокетам.

можно конкретнее?
я пробывал вариант где while(FCGX_Request_r(&req) == 0) у каждого потока свой, тогда все отлично работает, но такой вариант не катит

> - конкурентный доступ без блокировки к очереди в многопоточном приложении.

это все есть, в коде только не привел


"fastcgi в нескольких потоках"
Отправлено parad , 15-Мрт-12 16:26 
ну теперь понятней. )

у тебя:

while(FCGX_Accept_r(&req) == 0)
{
  ...
  handler_pool_.put_request(req);
  ...
}

А вот код из libfcgi:

int FCGX_Accept_r(FCGX_Request *reqDataPtr)
{
  FCGX_Finish_r(reqDataPtr);
  ...
}

где FCGX_Finish_r() все чистит, закрывает и освобождает память. тобишь поток не успевает ответить, а дескрипторы закрываются, память освобождается.

нужно дописать строчку:

while(FCGX_Accept_r(&req) == 0)
{
  ...
  handler_pool_.put_request(req);
  FCGX_InitRequest( req, ... );  // < по коду фцги - не занимается освобождением ресурсов, такчто подайдет.
  ...
}


"fastcgi в нескольких потоках"
Отправлено parad , 14-Мрт-12 13:52 
пс. почему топик в базах данных и sql?

"fastcgi в нескольких потоках"
Отправлено scx75 , 15-Мрт-12 11:07 
> пс. почему топик в базах данных и sql?

кто то перенес, я клал его в веб/CGI


"fastcgi в нескольких потоках"
Отправлено scx75 , 15-Мрт-12 14:42 
вообщем то виновато что происходит это в следующем порядке:

while(FCGX_Accept_r(&req) == 0)
{    
    req2 = req1;
    FCGX_InitRequest(&req, listen_socket, 0); // переинициализируем чтобы при FCGX_Accept_r не очистились стримы
    std::string str = "Content-Type: text/html;\r\n\r\nasads";
    FCGX_PutStr(str.c_str(), str.size(), req2.out);
    FCGX_Finish_r(&req2);
}


"fastcgi в нескольких потоках"
Отправлено parad , 15-Мрт-12 16:28 
верно.

"fastcgi в нескольких потоках"
Отправлено scx75 , 15-Мрт-12 16:57 
> верно.

ну да, до этого додумался, а в чем дальше трабл непонятно
в FCGX_InitRequest обнуляется память структуры и устанавливаются некоторые значения, но nginx почему то перестает принимает ответ от моей проги - выдает браузеру 502
как при memset'е может затронуться содержимое указателей?


"fastcgi в нескольких потоках"
Отправлено scx75 , 15-Мрт-12 16:58 
поправка:

while(FCGX_Accept_r(&req) == 0)
{    
    req2 = req;


"fastcgi в нескольких потоках"
Отправлено parad , 15-Мрт-12 20:06 
Поэксперементировал.

Натолкнуло на мысль что разработчики fastcgi пи**расы. Полез в код и понял что разбираюсь в людях:

Accept_r(reqDataPtr) дергает NewReader(reqDataPtr, ...) для создания потока in, NewReader(reqDataPtr, ...) дергает NewStream(reqDataPtr, ...), который содержит вот такие строчки:

--------------
...
FCGX_Stream_Data *data = (FCGX_Stream_Data *)Malloc(sizeof(FCGX_Stream_Data));
data->reqDataPtr = reqDataPtr; // Указатель на себя прикапывают. :)
...
--------------

Тобишь паттерт поставщика-потребители в твоей реализации не прокатит. Нельзя реквест трогать, пока не отработает.

Вот такой суперкастыль популярен в мире. )) Хоть сам реализовывай.


"fastcgi в нескольких потоках"
Отправлено scx75 , 15-Мрт-12 22:36 
удивляюсь, как вам не жалко времени на один из 100500 вопросов, спасибо) сейчас попробую понять что написали

"fastcgi в нескольких потоках"
Отправлено parad , 16-Мрт-12 12:03 
дело 10мин. сейчас на проекте где предстоит реализовывать компонент над фцги. уже проводил исследовательскую работу на подготовительном этапе - смотрел, пробывал, но в глубь не лазял. отвечая на этот вопрос сам опыту набрался, который скоро пригодится, тк тоже бы первым делом писал один поток-поставщик и пул потоков потребителей. и как следствие словил бы ту-же граблю. такчто незачто. )

"fastcgi в нескольких потоках"
Отправлено scx75 , 16-Мрт-12 11:57 
и все же не догнал, почему это влияет на результат?
там же новые стримы делаются, на стримы req2 никак не должны влиять, не?

"fastcgi в нескольких потоках"
Отправлено parad , 16-Мрт-12 12:06 
строчка: FCGX_Accept_r(&req) - вот этот указатель прикапывается внутрях. даже если мы req скопируем куда-либо и занулим его память, внутрях будет использована эта переменная.

"fastcgi в нескольких потоках"
Отправлено scx75 , 16-Мрт-12 14:45 
это то понятно, но нам не важна сама переменная, указатели на потоки то скопировали в другую, куда и производится вывод

req2 = req;
FCGX_InitRequest(&req, listen_socket, 0); // почистили req
FCGX_PutStr(str.c_str(), str.size(), req2.out); // выводим в req2, где указатели потоков сохранились и не очищались


"fastcgi в нескольких потоках"
Отправлено parad , 16-Мрт-12 15:58 
в том-то и дело, что переменная важна. они прикапывают указатель именно req. И через нее осуществляется доступ к содержимому реквеста:

FCGX_PutStr() содержит: stream->emptyBuffProc(stream, FALSE);

где, stream->emptyBuffProc - для in отока - NULL, для out потока - указатель на функцию EmptyBuffProc(), которая содержит строчки:

----------------------->
            *((FCGI_Header *) data->buff)
                    = MakeHeader(data->type,
                            data->reqDataPtr->requestId, cLen, eLen - cLen);
----------------------->
        if (write_it_all(data->reqDataPtr->ipcFd, (char *)data->buff, stream->wrNext - data->buff) < 0) {
----------------------->

тобишь, при записи в out поток используется указатель на структуру запроса для получения идентификатора запроса и дескриптора сокета. Т.к. указатель смотрит на req - в этих местах они для него - 0.


"fastcgi в нескольких потоках"
Отправлено scx75 , 16-Мрт-12 16:45 
спасибо, добрый чел, теперь дошло)

"fastcgi в нескольких потоках"
Отправлено scx75 , 16-Мрт-12 21:35 
вставил костыль, где меняю этот указатель на адрес req2 - теперь все пашет

"fastcgi в нескольких потоках"
Отправлено parad , 17-Мрт-12 15:02 
не забудь что там еще err и in потоки есть. а вообще хреново костыль костылем закрывать.

"fastcgi в нескольких потоках"
Отправлено scx75 , 19-Мрт-12 00:27 
куда теперь деваться, какие еще варианты многопоточности с одним приемником можно тогда придумать?