The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"fastcgi в нескольких потоках"
Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (Базы данных, SQL)
Изначальное сообщение [ Отслеживать ]

"fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 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 на си

Ответить | Правка | Cообщить модератору

Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "fastcgi в нескольких потоках"  +/
Сообщение от parad (ok) on 14-Мрт-12, 13:46 
лучше бы код привел, а не на память как-то так. зае*бись вопросы пошли.

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

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

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

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

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

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

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

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

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

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

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

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

Ответить | Правка | ^ к родителю #1 | Наверх | Cообщить модератору

6. "fastcgi в нескольких потоках"  +/
Сообщение от parad (ok) on 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, ... );  // < по коду фцги - не занимается освобождением ресурсов, такчто подайдет.
  ...
}

Ответить | Правка | ^ к родителю #4 | Наверх | Cообщить модератору

2. "fastcgi в нескольких потоках"  +/
Сообщение от parad (ok) on 14-Мрт-12, 13:52 
пс. почему топик в базах данных и sql?
Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

3. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 15-Мрт-12, 11:07 
> пс. почему топик в базах данных и sql?

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

Ответить | Правка | ^ к родителю #2 | Наверх | Cообщить модератору

5. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 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);
}

Ответить | Правка | ^ к родителю #0 | Наверх | Cообщить модератору

7. "fastcgi в нескольких потоках"  +/
Сообщение от parad (ok) on 15-Мрт-12, 16:28 
верно.
Ответить | Правка | ^ к родителю #5 | Наверх | Cообщить модератору

8. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 15-Мрт-12, 16:57 
> верно.

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

Ответить | Правка | ^ к родителю #7 | Наверх | Cообщить модератору

9. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 15-Мрт-12, 16:58 
поправка:

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

Ответить | Правка | ^ к родителю #5 | Наверх | Cообщить модератору

10. "fastcgi в нескольких потоках"  –1 +/
Сообщение от parad (ok) on 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; // Указатель на себя прикапывают. :)
...
--------------

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

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

Ответить | Правка | ^ к родителю #9 | Наверх | Cообщить модератору

11. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 15-Мрт-12, 22:36 
удивляюсь, как вам не жалко времени на один из 100500 вопросов, спасибо) сейчас попробую понять что написали
Ответить | Правка | ^ к родителю #10 | Наверх | Cообщить модератору

13. "fastcgi в нескольких потоках"  +/
Сообщение от parad (ok) on 16-Мрт-12, 12:03 
дело 10мин. сейчас на проекте где предстоит реализовывать компонент над фцги. уже проводил исследовательскую работу на подготовительном этапе - смотрел, пробывал, но в глубь не лазял. отвечая на этот вопрос сам опыту набрался, который скоро пригодится, тк тоже бы первым делом писал один поток-поставщик и пул потоков потребителей. и как следствие словил бы ту-же граблю. такчто незачто. )
Ответить | Правка | ^ к родителю #11 | Наверх | Cообщить модератору

12. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 16-Мрт-12, 11:57 
и все же не догнал, почему это влияет на результат?
там же новые стримы делаются, на стримы req2 никак не должны влиять, не?
Ответить | Правка | ^ к родителю #10 | Наверх | Cообщить модератору

14. "fastcgi в нескольких потоках"  +/
Сообщение от parad (ok) on 16-Мрт-12, 12:06 
строчка: FCGX_Accept_r(&req) - вот этот указатель прикапывается внутрях. даже если мы req скопируем куда-либо и занулим его память, внутрях будет использована эта переменная.
Ответить | Правка | ^ к родителю #12 | Наверх | Cообщить модератору

15. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 16-Мрт-12, 14:45 
это то понятно, но нам не важна сама переменная, указатели на потоки то скопировали в другую, куда и производится вывод

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

Ответить | Правка | ^ к родителю #14 | Наверх | Cообщить модератору

16. "fastcgi в нескольких потоках"  +/
Сообщение от parad (ok) on 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.

Ответить | Правка | ^ к родителю #15 | Наверх | Cообщить модератору

17. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 16-Мрт-12, 16:45 
спасибо, добрый чел, теперь дошло)
Ответить | Правка | ^ к родителю #16 | Наверх | Cообщить модератору

18. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 16-Мрт-12, 21:35 
вставил костыль, где меняю этот указатель на адрес req2 - теперь все пашет
Ответить | Правка | ^ к родителю #16 | Наверх | Cообщить модератору

19. "fastcgi в нескольких потоках"  +/
Сообщение от parad (ok) on 17-Мрт-12, 15:02 
не забудь что там еще err и in потоки есть. а вообще хреново костыль костылем закрывать.
Ответить | Правка | ^ к родителю #18 | Наверх | Cообщить модератору

20. "fastcgi в нескольких потоках"  +/
Сообщение от scx75 (ok) on 19-Мрт-12, 00:27 
куда теперь деваться, какие еще варианты многопоточности с одним приемником можно тогда придумать?
Ответить | Правка | ^ к родителю #19 | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру