Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблемы с переносимостью(Поток, функция) 
:(
    Опции темы
TGrey
Дата 4.10.2009, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 1.12.2007

Репутация: нет
Всего: 1



Здравствуйте, делаем с другом авторизатор для чата. Отдельные модули писали в VC после чего я сделал интерфейс в Борланде и интегрировал все части. У меня работает все хорошо, ну относительной той части, что должно работать, а вот у друга сразу же возникают проблемы.
1)Для вывода текста используем CppWebBrowser у меня все работает отлично у друга при вызове функции CppWebBrowser::Refresh() программа крашится.
2)Используем Сокеты для приема данных, как задержку я установил Sleep. Но поскольку он усыпляет основной поток, я создаю другой и он уже ловит сообщения. У меня по прежнему все хорошо, у друга, Слип действует на оба потока. Причем когда у него была предыдущая версия с неверным алгоритмом обработки строк Слип там действовал, как нужно, после того, как я переделал алгоритм, который никаким образом не относится к потокам и скинул новую версию другу, начался этот прикол со Слипом(только у него).

Попробовал скинуть готовый проект при запуске пишет обращение к запрещенной памяти(я полагаю Refresh() в браузере) и программа ложится.

Кто знает как с этим боротся, подскажите пожалуйста. 
PM MAIL   Вверх
GoldFinch
Дата 4.10.2009, 18:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 15
Всего: 26



TGrey, код покажи
PM MAIL ICQ   Вверх
TGrey
Дата 4.10.2009, 18:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 1.12.2007

Репутация: нет
Всего: 1



Кода очень много... Вот та часть, где основная проблема
Код

void Connector::CLogin()
{
    if( connect(to, (sockaddr*)&adr, sizeof(adr)) != SOCKET_ERROR)
        //cout<<"Connecting..."<<endl;
    if( send(to, login, strlen(login), 0) != 0 )
        //cout<<"Login Attempt"<<endl;

    Sleep(7000);
    recv(to, resp2, 20000, 0);            //RECV LogIn answer
    Sleep(2000);

    SetCid(resp2);
    SetUid(resp2);

    SetGet1(cid, uid);

    memset(resp2, 0, sizeof(resp2) );
    send(to, get1, strlen(get1), 0 );        
    Sleep(5000);
    recv(to, resp2, sr, 0);

    char *str=cutform(resp2);

    SetNewUid(str);
    //cout<<"NEW UID: "<<newuid<<endl;

    SetGet2(cid, newuid);
    memset(resp2, 0, sizeof(resp2) );
    send(to, get2, strlen(get2), 0);

        Sleep(2000);
        //ChatWindow->Recv->Enabled = true;
        //while(1){}
    /*string fd;      //For Delete
    int fdp;        //For Delete Pos
        string fptb;    //First packet temp buffer
    while( WORK )
    {
        //Sleep(2000);
        recv(to, resp2, sr, 0);
        fd = resp2;
        fdp = fd.find("<body onLoad");
        if( fdp != -1 )
                {
            fd.erase(0, fdp);
                        fd.erase(0, fd.find("<script>m"));
                        fd.replace(0,1,"100\r\n<");
                }
        strcpy(resp2, fd.c_str());

               [color=red] ChatWindow->wb->Refresh();[/color]
               //MessageBox(NULL, resp2, "Resp2", 0);
               Together(resp2);
                //Form1->wb->Refresh();
        memset(resp2, 0, sr);
        //Sleep(3000);
    }*/
}


Вот тут Рефреш у друга вызывает краш, а Слипы усыпляют не только свой поток. Сейчас попробовал перевести со Слипов в Таймер, но Сокет блокирующий и поэтому пока он ждет данных программа тоже висит.
Думаю сейчас еще попробовать вернуть все в поток, но вместо Слипов проверять fd_set на чтение сокетом инфы.

Поток создается нажатием на кнопку
Код

int WINAPI WorkThread(void*)
{
        c.CInit();
        c.CLogin();
        return 0;
}
//---------------------------------------------------------------------------
void __fastcall TChatWindow::Button1Click(TObject *Sender)
{
        TVariant url = w1.c_str();
        wb->Navigate2(&url, NULL, NULL, NULL, NULL);
        WT = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&WorkThread, NULL, NULL, NULL);
}

PM MAIL   Вверх
TGrey
Дата 4.10.2009, 19:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 1.12.2007

Репутация: нет
Всего: 1



Блин..... Перейдя на select и убрав все Слипы, обнаружил гадость(( У друга все в том же месте главное окно висит. Если там всунуть МесседжБокс то пока он открыт окном можно манипулировать и просмотреть данные, но как только жму ОК на нем программа снова переходит в затупленный режим.
Остается вариант, что блокирующий сокеты просто напросто блочат окно пока ждут инфу. Но интересно, как они это делают из другого потока?!



---------------------------------------------
Теперь еще лучше, поменял режим на неблокирующий читаю инфу и темнемение программа всеравно виснет, хоть и не постоянно но 1 раз в 5 сек точно.

Новый код
Код

void Connector::CLogin()
{
    if( connect(to, (sockaddr*)&adr, sizeof(adr)) != SOCKET_ERROR)
        //cout<<"Connecting..."<<endl;
    if( send(to, login, strlen(login), 0) != 0 )
        //cout<<"Login Attempt"<<endl;

    Sleep(7000);
    recv(to, resp2, 20000, 0);            //RECV LogIn answer
    Sleep(2000);

    SetCid(resp2);
    SetUid(resp2);

    SetGet1(cid, uid);

    memset(resp2, 0, sizeof(resp2) );
    send(to, get1, strlen(get1), 0 );        
    Sleep(5000);
    recv(to, resp2, sr, 0);

    char *str=cutform(resp2);

    SetNewUid(str);
    //cout<<"NEW UID: "<<newuid<<endl;

    SetGet2(cid, newuid);
    memset(resp2, 0, sizeof(resp2) );
    send(to, get2, strlen(get2), 0);

        unsigned long st=1;
        ioctlsocket(to, FIONBIO, &st);
        Sleep(2000);
        //ChatWindow->Recv->Enabled = true;
    string fd;      //For Delete
    int fdp;        //For Delete Pos
        string fptb;    //First packet temp buffer

        fd_set fs;
        timeval tot;
        tot.tv_sec = 0;
        tot.tv_usec = 1000;

    while( WORK )
    {
                FD_ZERO(&fs);
                FD_SET(to, &fs);
                select(0, &fs, NULL, NULL, &tot );
        //Sleep(2000);
        if( FD_ISSET(to, &fs) )
        {
        recv(to, resp2, sr, 0);
        fd = resp2;
        fdp = fd.find("<body onLoad");
        if( fdp != -1 )
                {
            fd.erase(0, fdp);
                        fd.erase(0, fd.find("<script>m"));
                        fd.replace(0,1,"100\r\n<");
                }
        strcpy(resp2, fd.c_str());

                //ChatWindow->wb->Refresh();
               // if( !MapInited )
               //         fptb = resp2;
               //MessageBox(NULL, resp2, "Resp2", 0);
               Together(resp2);
        //checkbuffer(resp2);
                //Form1->wb->Refresh();
                //Form1->wb->ScrollBy(0,1000);
        memset(resp2, 0, sr);
        //Sleep(3000);
        }
    }
}


Это сообщение отредактировал(а) TGrey - 4.10.2009, 20:29
PM MAIL   Вверх
xvr
Дата 5.10.2009, 12:03 (ссылка) |  (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



1) Очень странные if'ы в начале Connector::CLogin - рекомендуется им приделать какое нибудь тело (хотя бы пустое - в виде ;). Пока у них телом выступает второй if и Sleep(7000)
2) Вызывать VCL объекты (ChatWindow->wb->Refresh();) из тела thread'а нельзя - VCL на это не расчитанна. Пользуйтесь TThread и его методом Synchronize

PM MAIL   Вверх
bsa
Дата 5.10.2009, 12:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Согласен с xvr.
TGrey, описываемое тобой явление очень похоже на случай "гонки" ("соревнование" или "race condition"), когда идет одновременная работа с одними и теми же данными из разных потоков без синхронизации.
PM   Вверх
TGrey
Дата 5.10.2009, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 1.12.2007

Репутация: нет
Всего: 1



Ах да, if. Переносил с консоли вывод закоментил тело забыл дописать, но по сути это не должно быть ключевой проблемой.
Спасибо за подсказку я не знал, что обычные потоки не подходят для VCL. Сейчас попробую с TThread.
И какую же функцию пихать в Синхронизацию? Как видите я все запихал в класс и что тогда синхронизировать и как это лучше всего сделать?

И тогда такой вопрос, почему же у меня все замечательно работает? smile 

И кстати класс у меня с VC. То есть для синхронизации нужно переписать его в BCB и тогда возможно будет Синхронизировать его функции. Так?

-------------------------
Так-с совсем забыл про тестовые выводы данных из потока. Закоментил их + Рефреш обрабатываю таймером в зависимости от значения булевой переменной и теперь работает без глюков.(Поток оставил старый)
Пока все хорошо. Возникнут проблемы вернусь спрошу. Спасибо. smile 

Это сообщение отредактировал(а) TGrey - 5.10.2009, 21:43
PM MAIL   Вверх
xvr
Дата 5.10.2009, 23:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(TGrey @ 5.10.2009,  17:28)
И какую же функцию пихать в Синхронизацию? Как видите я все запихал в класс и что тогда синхронизировать и как это лучше всего сделать?

Любую функцию. Все общение с VCL объектами можно делать ТОЛЬКО из такой функции. Т.е. схема действия такова
  •  Необходимые данные кладутся в переменные класса
  •  Вызывается функция через Synchronize
  •  Из этой функции данные из переменных класса (п1) переносятся в объекты VCL
  •  Перед выходом из функции желательно что бы данные в этих переменных класса были разрушены (особенно это касается AnsiString и пр)

Цитата

И тогда такой вопрос, почему же у меня все замечательно работает? smile 
Повезло. Пользователям может так не повезти  smile 

Цитата

И кстати класс у меня с VC. То есть для синхронизации нужно переписать его в BCB и тогда возможно будет Синхронизировать его функции. Так?
Да

Цитата

Рефреш обрабатываю таймером в зависимости от значения булевой переменной и теперь работает без глюков.(Поток оставил старый)
При таком подходе надо защищать доступ к булевской переменной из потока и основной программы (например через критическую секцию). Возможны гонки при установке/сбросе переменной. Или использовать атомарные операции (InterlockedExchange)


PM MAIL   Вверх
TGrey
Дата 6.10.2009, 11:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 1.12.2007

Репутация: нет
Всего: 1



Лучше через секцию) Т.к. с атомарными операциями дела я не имел.
С булевой работаю так:
Если сообщение пришло и нужно обновить чат, то ставлю ее в true
Таймер крутится проверяя ее значение, если оно true, то в теле таймера происходит Рефреш и переменная сбрасывается.

Будет ли достаточно в этот момент, когда переменная сбрасывается занести ее в Критическую секцию, это не позволит тому потоку продолжать принимать сообщения и выставлять переменную заново?
PM MAIL   Вверх
xvr
Дата 6.10.2009, 13:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(TGrey @ 6.10.2009,  11:37)
Лучше через секцию) Т.к. с атомарными операциями дела я не имел.
С булевой работаю так:
Если сообщение пришло и нужно обновить чат, то ставлю ее в true
Таймер крутится проверяя ее значение, если оно true, то в теле таймера происходит Рефреш и переменная сбрасывается.

Будет ли достаточно в этот момент, когда переменная сбрасывается занести ее в Критическую секцию, 

Нет, недостаточно. В секцию надо заключать установку этой переменной из потока, и проверку со сбросом (ОБЯЗАТЕЛЬНО вместе) из основной программы

PM MAIL   Вверх
TGrey
Дата 7.10.2009, 19:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 1.12.2007

Репутация: нет
Всего: 1



То есть когда я получаю данные и нужно установить переменную, я эту часть пихаю в секцию(это внутри класса), а в Таймере просто пишу проверку и сброс? Или я не понял?
PM MAIL   Вверх
xvr
Дата 7.10.2009, 23:10 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(TGrey @ 7.10.2009,  19:33)
То есть когда я получаю данные и нужно установить переменную, я эту часть пихаю в секцию(это внутри класса), а в Таймере просто пишу проверку и сброс?

Обе части, и в Таймере тоже. Секция предназначена для защиты доступа к общему ресурсу из РАЗНЫХ мест (потоков). Т.е. их (мест) должно быть как минимум 2  smile 
PM MAIL   Вверх
TGrey
Дата 8.10.2009, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 1.12.2007

Репутация: нет
Всего: 1



Хорошо. Еще раз спасибо smile 
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0571 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.