Жёсткая проблема с потоками

Тема в разделе "LANGS.C", создана пользователем Rascalspb, 25 ноя 2007.

  1. Rascalspb

    Rascalspb New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    46
    Адрес:
    СПб
    Суть задачи: есть функция, которая вычисляет чтото. Функция работает весьма долго. Надо пользователю предоставлять окно с инфой о прогрессе (хотя прогресс совсем не линеен, но хоть чтото) и возможностью отмены расчета.
    Сделал так: основной поток, который должен вернуцо в вызвавший код, создает 1 поток - расчетный. Дальше WaitForSingleObject на хэндл. Расчетный поток создает поток диалогового окна, которое сообщает о прогрессе. На окне кнопка отмены расчета. По кнопке киляется поток расчета. Поток диалога киляется после выхода из WaitForSingleObject. Собсно комбинаций много перепробовал для убийств. Какие случаи бывают - если в потоке диалога делаю ExitThread - то после 2х вызовов расчета подряд поток не умирает. Расчетный поток убивается, а диалоговый висит. Если делаю TerminateThread после Wait, то при следующем вызове есть 3 потока, но диалога нету... Вариаций хватает...
    Главная проблема: основной поток расчета после нескольких пересчетов зависает. Зависает вместе с диалогом... Причем я долго не мог понять где. Судя по всему вешается он на new. Должен заметить, расчет активно использует new и delete. В мсдн нашел интересное место

    For example, TerminateThread can result in the following problems:

    If the target thread owns a critical section, the critical section will not be released.
    If the target thread is allocating memory from the heap, the heap lock will not be released.

    Собсно вопрос - что делать? Как рулить долгим потоком...
     
  2. UTeX

    UTeX New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2007
    Сообщения:
    584
    код с управлением потоками давай
     
  3. Rascalspb

    Rascalspb New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    46
    Адрес:
    СПб
    Код (Text):
    1.     // начинаем поток расчета
    2.     calc_thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)CalcThreadProc, 0, 0, &calcthread_id);
    3.     // ждем окончания расчета, или же отмены расчета
    4.     WaitForSingleObject(calc_thread, INFINITE);
    5.  
    6.     TerminateThread(waitdialog_thread, -1);
    7.  
    8.     GetExitCodeThread(calc_thread, &calcthread_exit_code);
    9.     if(calcthread_exit_code == -1){
    10.         // в расчете произошла ошибка, или расчет отменили
    11.         NumOfPlates = 0;
    12.     }
    13.     else{
    14.         calculator->ExtractPlates(Plate_Points_X, Plate_Points_Y, Plates_Height);
    15.         NumOfPlates = plates_num;
    16.     }
    Код (Text):
    1. void CalcThreadProc ()
    2. {
    3.     plates_num = 0;
    4.     waitdialog_thread = 0;
    5.     DWORD tid;
    6.     waitdialog_thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ShowWaitDialog, 0, 0, &tid);
    7.     plates_num = calculator->Calculate();
    8.     SendMessage(waitdialog_wnd, WM_CLOSE, 0, 0);
    9.  
    10.     //KillTimer(waitdialog_wnd, 0);
    11.     //EndDialog(waitdialog_wnd, -1);
    12.     //TerminateThread(waitdialog_thread, 0);
    13.     ExitThread(0);
    14. }
    Код (Text):
    1. BOOL CALLBACK DialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    2. {
    3.     switch(message)
    4.     {
    5.     case WM_INITDIALOG:
    6.         waitdialog_wnd = hDlg;
    7.         SetTimer(hDlg, 0, 100, 0);
    8.        
    9.         return (TRUE);
    10.        
    11.     case WM_DESTROY:
    12.     case WM_CLOSE:
    13.         KillTimer(hDlg, 0);
    14.         TerminateThread(calc_thread, -1);
    15.         waitdialog_wnd = 0;
    16.         EndDialog(hDlg, -1);
    17.         //ExitThread(-1);
    18.         return (TRUE);
    19.        
    20.     case WM_COMMAND:
    21.         switch (LOWORD(wParam))
    22.         {
    23.         case IDC_CANCEL:
    24.             KillTimer(hDlg, 0);
    25.             TerminateThread(calc_thread, -1);
    26.             waitdialog_wnd = 0;
    27.             EndDialog(hDlg, -1);
    28.             //ExitThread(-1);
    29.  
    30.             return (TRUE);
    31.         }
    32.         return (FALSE);
    33.     }
    34.     return (FALSE);
    35. }
     
  4. qwerty_9876

    qwerty_9876 New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2007
    Сообщения:
    47
    >>Главная проблема: основной поток расчета после нескольких пересчетов зависает. Зависает вместе с диалогом... >>Причем я долго не мог понять где. Судя по всему вешается он на new. Должен заметить, расчет активно использует >>new и delete.

    На счет CRT Рихтер говорит:

    "Чтобы многопоточные программы, использующие библиотеку С/С++, работали корректно, требуется создать специальную структуру данных и связать ее с каждым потоком, из которого вызываются библиотечные функции Более того, они должны знать, что, когда Вы к ним обращаетесь, нужно просматривать этот блок данных в вызывающем потоке чтобы не повредить данные в каком-нибудь другом потоке
    Так откуда же система знает, что при создании нового потока надо создать и этот блок данных. Ответ очень прост не знает и знать не хочет Вся ответственность — исключительно на Вас Если Вы пользуетесь небезопасными в многопоточной среде функциями, то должны создавать потоки библиотечной функцией _begmthreadex, а не Windows-функцией CreateThread"
     
  5. UTeX

    UTeX New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2007
    Сообщения:
    584
    короче можно перегрузить alloc и free как и было выше сказно и попробовать

    отпишись если помогло
     
  6. Rascalspb

    Rascalspb New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    46
    Адрес:
    СПб
    я new и delete'ю класцы и структуры. мне проще добавить глобальные флаги, которые бы сообщали о сбросе расчета. и в функции расчета просто на итерациях (правда во многих циклах) проверять этот флаг. потому как косяк 99.999% именно в работе с ъхипом, а именно в моменты киляния потока, находящегося в кернеле. т.е. мне проще пожертвовать несколькими секундами паузы между нажатием на конпку Cancel и реальной остановкой потока, но гарантировано человечной, нежели переписывать кодес =)
    или вариант морозить гуи поток на моменты вызова new и delete, перегрузив их. чтобы не попасца в неудобный момент. тока это имхо больше ресурсов требует.
    зы: пока не хочеца парица со структурами для потоков, ибо заказчик просит не задерживаца, а тема для меня новая, лучше как нить по деревенски сделоть. жду рекомендаций. седня уже спать буду, завтра с утреца приступлю.
     
  7. Rascalspb

    Rascalspb New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    46
    Адрес:
    СПб
    короч исправил по способу добавления флага останова. муторно и потери скорости канешн будут, но пока не замерял. самое главное - работает все нормально.

    Код (Text):
    1. calc->SetInterruptCalc(true);
    2. WaitForSingleObject(calc_thread, INFINITE);
    3. waitdialog_wnd = 0;
    4. EndDialog(hDlg, -1);
    и внутри класса

    Код (Text):
    1. if(interrupt_calc == true){
    2.     ExitThread(-1);
    3. }
    Типа диалог висит, пока поток расчета не обработает флаг останова. Красивше делать некогда, может потом.
    ЗЫ: спасибо за советы
     
  8. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    дальше названия темы не осилил, много букв, ошибка в названии темы режет глаз )
     
  9. Rascalspb

    Rascalspb New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    46
    Адрес:
    СПб
    превед астег =) я вообще хотел написать "жоская"
     
  10. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Rascalspb
    Я бы вообще по-другому написал: в первом потоке создается диалог с прогресс-баром и вертится цикл обработки сообщений, во втором есть хэндл прогрессбара. А вообще код у вас такой же как язык (албанский).
    _beginthreadex, если пишете с применением CRT.
    Такое вообще не советуют делать. Лучше return 0, а еще лучше _endthreadex(0);
    Зачем? Не лучше ли послать сигнал о том, что надо "сворачиваться"?
    MSDN: ThreadProc callback function
    Наверняка что-нибудь еще пропустил.
     
  11. UTeX

    UTeX New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2007
    Сообщения:
    584
    TLS ?
     
  12. Rascalspb

    Rascalspb New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    46
    Адрес:
    СПб
    censored
    Я предпочитаю использовать апи. из crt - тока new и delete, ито ибо пишу с классами.
    На счет завершения потока - сигналить то сигналить, но в функции много потенциально опасных мест, в которых может повесицо поток. В этом смысле канешно джава рулит, и поэтому все равно придеца сделать кнопку в окошке ожидания - hard kill. Хотя итак много мест зависающих исправил.

    ну я прописал ExitThread, а у трэдпроца возвращаемое значение важно лишь как сигнал о коде завершения потока. Так что в принципе работать будет итак, но канешн некрасиво - поправлю

    хз. покажи, как это поможет. главный косяк я описал - терминатить тупо незя - иначе косяки в кернеле. как тлс может помочь убить поток в первый же удобный момент(када снялись все блокировки, вышли из всех критических секций итп), но без проверок в каждом цикле, работающим в потоке
     
  13. qwerty_9876

    qwerty_9876 New Member

    Публикаций:
    0
    Регистрация:
    10 апр 2007
    Сообщения:
    47
    >>из crt - тока new и delete, ито ибо пишу с классами

    Если предпочитаешь АПИ то не используй вообще CRT(пиши свой new delete, если есть глоб. экземпляры классов пиши свои реализации инициализации/завершения, если есть код с плавающей точкой тоже нужна инициализация среды обработки ошибок и тд. ).
    Иначе:
    Как вариант для чистого АПИ в VC можно использовать _ATL_MIN_CRT и тогда будет тебе немного этого вкусного безопасного CRT.