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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Потоки WinApi и GCC, Обуздание потоков 
:(
    Опции темы
Dem_max
Дата 15.7.2012, 18:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 4
Всего: 39



Цитата

то никаких termitate не нужно

Да ну ???? и что же случается с зависшим потоком ???? он так и остается висеть в памяти ???


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Randajad
Дата 15.7.2012, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Почему он зависнет? Есть thread::join, которое и нужно юзать.
PM MAIL   Вверх
Dem_max
Дата 15.7.2012, 18:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 4
Всего: 39



Ну потому что например в потоке бесконечный цикл запущен. 


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Randajad
Дата 15.7.2012, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Ну запущен - пусть делает себе бесконечный цикл, раз надо. Что такого?
PM MAIL   Вверх
Dem_max
Дата 15.7.2012, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 4
Всего: 39



Ну поток должен быть завершен, если это требуется.
Вопрос как его завершить ???


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
borisbn
Дата 15.7.2012, 20:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 22
Всего: 135



Цитата(Dem_max @  15.7.2012,  04:58 Найти цитируемый пост)
Кстати забыл сказать, крайне не рекомендую создавать поток в конструкторе класса

вот был (и остаюсь) точно такого же мнения.... но, когда увидел boost::/std:: thread - был немного удивлён. Там как раз наоборот - запускают поток в конструкторе (и мало того - в деструкторе - не ожидают завершения работы потока)... странно...


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
NYX
Дата 15.7.2012, 20:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



В будущем конечно я уже буду использовать готовые реализации объектов-потоков. Но пока что надо разобраться в тонкостях этих потоков. В любооом случае, это надо знать smile
...
Все, разобрался с деструктором. Все арбайтен! Там с помощью флагов теперь поток размораживется и если подвызов потока не произошел, то поток завершается без подвызова. Если поток по каким либо причинам завис, то деструктор не даст удалить объет до того момента пока поток не развиснет. Так что поток вечен в этом плане. Если надо предотвратить работу потока (возможно принудительно) то через Stop в аргументе которого указывает интервал ожидания smile Осталось терь разобарться с синхронизацией и придумать коллектор объектов-потоков ответсвенный за всех сынов своих. А может даже и возможность пазла в коллекторе под еще один, для контроля целой матрицы потоков. Кстати на случай необходимости, можно ведь повесить флаг в конструкторе, мол "Запустить его сразу? Или ждать вызова Start?"

Это сообщение отредактировал(а) NYX - 15.7.2012, 20:44
--------------------
'long long long' is too long for GC
PM   Вверх
NYX
Дата 15.7.2012, 20:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Прототип
Код

namespace Z {
    namespace Basis {
        class Thread;

        typedef unsigned long (*thread_action)(void *Argument, Thread *Parent); // ...........................................................> Функция вызываемая потоком

        struct thread_argument {
            thread_action Action; // .........................................................................................................> Указатель функции для вызова потоком
            void *Argument; // ...............................................................................................................> Аргумент для функции вызываемой потоком
        };

        class Thread {
        public:

            Thread(thread_action Action, void *Argument, unsigned long *Return); // ..........................................................> Конструктор
            /* Конструктор объекта потока принимающий в качестве аргументов указатель на функцию подвызова потока, указатель на аргументы
             * передаваемые потоку (пользовательской функции - подвызову потока). Параметр Return является указателем на вшенюю переменную
             * для возвращаемого значения потока. В качестве данного аргумента можно указать NULL. В любом из случаев, объект потока вернет
             * код выхода потока при вызове GetExitCode если поток завершен. */

            ~Thread(); // ....................................................................................................................> Деструктор
            /* Деструктор не завершает поток принудительно, он ожидает завершение потока. Если поток не была запущен, то деструктор завершает
             * поток без его выполнения подвызова (рекомендуемым способом, без применения TerminateThread) */

            unsigned int Start(); // .........................................................................................................> Запустить поток
            /* Метод размораживает поток в случае вызова после конструктора. Если вызов повторный, проверяется активность потока. Если поток
             * завершен, производится сброс объекта и повторный вызов потока. Если поток еще выполняется, данный вызов игнорируется */

            bool Pause(unsigned int Delay); // ...............................................................................................> Заморозить поток
            /* Функция замораживает поток. В случае если Delay равен нулю, поток замораживается до вызова Start. Если Delay больше нуля, то
             * поток замораживается на периуд указанный в Delay. */

            bool Stop(unsigned int Wait); // .................................................................................................> Остановить поток
            /* Принудительное завершение потока. Параметр Wait Указывает количество десятых секунды ожидания. Если значение Wait равное нулю,
             * то поток завершается вызовом TerminateThread с кодом выхода 0. Если Wait больше нуля, то функция ожидает заданный периуд в
             * десятых долях секунды, и если поток не завершился, вызывается TerminateThread с кодом выхода равным 0 */

            bool Wait(); // ..................................................................................................................> Ожидание завершения потока
            /* Проверяет активность объекта. (!) Может привести к зависанию главного потока в случае если не был произведен вызов Start */

            unsigned long GetID(); // ........................................................................................................> Взять идентификатор потока
            /* Возвращает идентификатор потока */

            void *GetHandle(); // ............................................................................................................> Взять дескриптор потока
            /* Возвращает дескриптор (адрес объекта ядра) потока */

            unsigned long GetExitCode(); // ..................................................................................................> Взять код возврата потока
            /* Возвращает код выхода потока. Если поток не завершен, возвращается значение 0. Для проверки завершенности потока можно
             * использоваться функцию Wait, но при условии предварительного вызова Start */

        private:
            thread_argument _ThreadArgument; // ..............................................................................................> Структура аргументов для потока
            unsigned long *_Return; // .......................................................................................................> Указатель на значение возвращаемое потоком
            unsigned long _ThreadExitCode; // ................................................................................................> Код возврата потока

            bool _ThreadStartControl; // .....................................................................................................> Флаг контроля запуска потока
            bool _ThreadCompleted; // ........................................................................................................> Флаг завершенности потока

            unsigned long _ThreadID; // ......................................................................................................> Идентификатор потока
            void *_ThreadHandle; // ..........................................................................................................> Дескриптор потока

            static unsigned long __stdcall _ThreadFunction(void *Argument); // ...............................................................> Функция потока
        };
    }
}


Реализация
    Функция _Format это аналог sprintf тока возвращающий string, вместо аргумента указателя результирующей строки str 
    Функция IternalShellError это функция которая выводит ошибку либо в консоль, либо в MessageBox и завершает приложение ExitProccess
    Оповещение об ошибке на скорую руку smile
Код

Z::Basis::Thread::Thread(thread_action Action, void *Argument, unsigned long *Return) {
    _ThreadArgument.Action = Action; // ......................................................................................................> Присвоения указателя пользовательской функции
    _ThreadArgument.Argument = Argument; // ..................................................................................................> Присвоение указателя на аргументы
    if (Return == NULL) { // .................................................................................................................> Проверка указателя на внешнюю переменную кода выхода ->
        _Return = &_ThreadExitCode; // .......................................................................................................> Берется указатель переменной объекта
        _ThreadExitCode = 0; // ..............................................................................................................> Оонуление переменной кода возврата объекта
    } else {
        _Return = Return; // .................................................................................................................> Присваивается указатель на внешнюю переменную
        *_Return = 0; // .....................................................................................................................> Обнуление внешней переменной кода возврата
    }

    _ThreadStartControl = false; // ..........................................................................................................> Флаг контроля запуска потока
    _ThreadCompleted = false; // .............................................................................................................> Флаг завершенности потока

    _ThreadID = 0; // ........................................................................................................................> Обнуление идентификатора потока
    _ThreadHandle = CreateThread(NULL, 0, &_ThreadFunction, this, CREATE_SUSPENDED, &_ThreadID); // ..........................................> Создание потока
    if (_ThreadHandle == NULL) { // ..........................................................................................................> Дескриптор потока пуст - поток не создан
        Z::InternalShellError("Failed to create thread");
    }
}

Z::Basis::Thread::~Thread() {
    if (!_ThreadStartControl) { // ...........................................................................................................> Проверка флага контроля запуска потока ->
        _ThreadStartControl = true; // .......................................................................................................> Поток неактивен - необходим запуск с завершением
        Start(); // ..........................................................................................................................> Запуск а завершением
    }

    bool ThreadWork = true; // ...............................................................................................................> Флаг активности потока
    while (ThreadWork) { // ..................................................................................................................> Цикл проверки активности потока ->
        unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, 100); // ...............................................................> Проверка занятости объекта
        if (WaitResult == WAIT_OBJECT_0) // ..................................................................................................> Поток завершился ->
            ThreadWork = false; // ...........................................................................................................> Выход из цикла проверки активности
        else if (WaitResult == WAIT_FAILED) // ...............................................................................................> Ошибка проверки активности потока
            Z::InternalShellError(_Format("Failed to wait thread %lu", GetLastError()).c_str()); // ..........................................> Оповещение об ошибке
    }
    
    if (CloseHandle(_ThreadHandle) == 0) // ..................................................................................................> Попытка закрыть дескриптор потока
        Z::InternalShellError(_Format("Failed to close thread handle %lu", GetLastError()).c_str());
    
    GetExitCode(); // ........................................................................................................................> Взятие кода возврата потока
}

unsigned int Z::Basis::Thread::Start() {
    if (_ThreadCompleted) { // ...............................................................................................................> Проверка завершенности потока ->
        _ThreadStartControl = false; // ......................................................................................................> Сброс флага контроля запуска потока
        _ThreadCompleted = false; // .........................................................................................................> Сброс флага завершенности потока
        _ThreadID = 0; // ....................................................................................................................> Обнуление идентификатора потока
        _ThreadHandle = CreateThread(NULL, 0, &_ThreadFunction, this, 0, &_ThreadID); // .....................................................> Создание и запуск потока
        return 2; // .........................................................................................................................> Новый поток создан и запущен на выполнение
    }

    unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, 0); // .....................................................................> Проверка занятости объекта
    if (WaitResult == WAIT_OBJECT_0) // ......................................................................................................> Поток завершился ->
        return 0;
    else if (WaitResult == WAIT_FAILED) // ...................................................................................................> Ошибка проверки активности потока
        Z::InternalShellError(_Format("Failed to wait thread on start %lu", GetLastError()).c_str()); // .....................................> Оповещение об ошибке

    if (ResumeThread(_ThreadHandle) == -1) // ................................................................................................> Попытка разморозки потока
        Z::InternalShellError(_Format("Failed to resume thread %lu", GetLastError()).c_str()); // ............................................> Оповещение об ошибке
    return 1;
}

bool Z::Basis::Thread::Pause(unsigned int Delay) {
    unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, 0); // .....................................................................> Проверка занятости объекта
    if (WaitResult == WAIT_OBJECT_0) // ......................................................................................................> Поток завершился ->
        return false;
    else if (WaitResult == WAIT_FAILED) // ...................................................................................................> Ошибка проверки активности потока
        Z::InternalShellError(_Format("Failed to wait thread on pause %lu", GetLastError()).c_str()); // ......................................> Оповещение об ошибке

    if (SuspendThread(_ThreadHandle) == -1) // ...............................................................................................> Попытка заморозки потока
        Z::InternalShellError(_Format("Failed to suspend thread %lu", GetLastError()).c_str()); // ...........................................> Оповещение об ошибке
    
    if (Delay > 0) { // ......................................................................................................................> Если время заморозки больше нуля ->
        Sleep(Delay); // .....................................................................................................................> Задержка перед разморозкой
        Start(); // ..........................................................................................................................> Разморозка потока
    }
    
    return true;
}

bool Z::Basis::Thread::Stop(unsigned int Wait) {
    for (unsigned int Index = 0; Index < Wait; Index++) { // .................................................................................> Цикл ожидания потока ->
        if (WaitForSingleObject(_ThreadHandle, 100) == 0) { // ...............................................................................> Итерация цикла ожидания ->
            GetExitCodeThread(_ThreadHandle, _Return); // ....................................................................................> Взятие кода возврата потока
            return true;
        }
    }
    
    TerminateThread(_ThreadHandle, 0); // ....................................................................................................> Принудительное завершение потока
    GetExitCode(); // ........................................................................................................................> Взятие кода возврата потока
    return false;
}

bool Z::Basis::Thread::Wait() {
    unsigned long WaitResult = WaitForSingleObject(_ThreadHandle, INFINITE); // ..............................................................> Ожидание завершения потока
    if (WaitResult == WAIT_OBJECT_0) // ......................................................................................................> Потока завершился
        return true;
    else if (WaitResult == WAIT_FAILED)
        Z::InternalShellError(_Format("Failed to wait thread %lu", GetLastError()).c_str()); // ..............................................> Оповещение об ошибке
}

unsigned long Z::Basis::Thread::GetID() {
    return _ThreadID;
}

void *Z::Basis::Thread::GetHandle() {
    return _ThreadHandle;
}

unsigned long Z::Basis::Thread::GetExitCode() {
    GetExitCodeThread(_ThreadHandle, _Return); // ............................................................................................> Взятие кода возврата потока
    return *_Return;
}

unsigned long __stdcall Z::Basis::Thread::_ThreadFunction(void* Argument) {
    Thread *Parent = reinterpret_cast<Thread*> (Argument); // ................................................................................> Приведение типа указателя

    if (Parent->_ThreadStartControl) // ......................................................................................................> Проверка флага контроля запуска потока ->
        return 0; // .........................................................................................................................> Запуск отменяется - завершение потока
    else // ..................................................................................................................................> Запуск разрешен ->
        Parent->_ThreadStartControl = true; // ...............................................................................................> Отметка о произведенном запуске потока

    unsigned long Return = Parent->_ThreadArgument.Action(Parent->_ThreadArgument.Argument, Parent); // ......................................> Вызов пользовательской функции потока
    return Return; // ........................................................................................................................> Возврат значения пользовательской функции потока
}


Добавлено @ 20:58
Там в Pause используется Sleep. Дело неблагодарное, так как заснет все, не только замораживаемый поток smile Это не к чему. Может имеет смысл для онной реализации использовать поток коллектора (единственный на объект коллектора...) или ваще отнять эту возможность. В общем, это я так, для ассортимента вставил, Sleep этот.

main
Код

unsigned long ThreadFunction(void *Argument, Z::Basis::Thread *Parent) {
    string *ArgumentString = reinterpret_cast<string*>(Argument);
    printf("Im a ID:%lu HANDLE:%p thread with a `%s` argument and im guess return 666 value. It's there? \n", Parent->GetID(), Parent->GetHandle(), ArgumentString->c_str());
    return 666;
}

int main(int argc, char** argv) {
    system("cls");
    unsigned long Ret = 0;
    string StringForThread("ArgString");
    Z::Basis::Thread _Thread_A(&ThreadFunction, &StringForThread, NULL);
    Z::Basis::Thread _Thread_B(&ThreadFunction, &StringForThread, NULL);
    
    _Thread_A.Start();
    _Thread_A.Wait();
    
    printf("Ret is %lu\n", _Thread_A.GetExitCode());
    if (_Thread_A.GetExitCode() == 666)
        printf("That's OK!");
    
    return 0;
}


Это сообщение отредактировал(а) NYX - 16.7.2012, 01:49
--------------------
'long long long' is too long for GC
PM   Вверх
Randajad
Дата 15.7.2012, 23:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



atomic_bool и в бесконечном цикле в потоке ее проверять. Разве не  так? Или вы хотите с помощью Termonate его жестоко убить? smile
PM MAIL   Вверх
NYX
Дата 16.7.2012, 00:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



атомарный флаг.... эммм... а куда его пихать то? В перерывах выполнения пользовательской функции-потока? Не, я понял.... но почему атомарный? Кто еще будет читать\писать флаг?  smile  о боги я еще не в курсе синхронизации... был перерыв на сон. Счас активизировался для пожирания информации.

Это сообщение отредактировал(а) NYX - 16.7.2012, 00:12
--------------------
'long long long' is too long for GC
PM   Вверх
Alca
Дата 16.7.2012, 00:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 7
Всего: 50



Цитата

Всегда побаивался потоков, а счас решил напрямую в лоб с ними бороться


https://bitbucket.org/skynowa/xlib/src/7091...Sync/CxThread.h
https://bitbucket.org/skynowa/xlib/src/7091...nc/CxThread.cpp

Это сообщение отредактировал(а) Alca - 16.7.2012, 00:17


--------------------
PM WWW ICQ Skype Jabber   Вверх
Randajad
Дата 16.7.2012, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Это был на вопрос участника выше: что делать в бесконечном цикле. smile
Проверять эту атомарную переменную и завершать выполнение цикла, если она, например, == true. Зачем атомарную? Компилятор может ее выкинуть из цикла, ибо посчитает, что она не изменяется. Хотя. Можно сделать не атомарную, а volatile.
PM MAIL   Вверх
NYX
Дата 16.7.2012, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



На GCC нет _beginthread :(
Но для общего принципа исходники интересны. Гранд рахмад за писчу для ума! Да и ваще всем спасибо за помосч smile Буду ковыряться, постепенно писать о результах прогресса.
КСТАТИ! Об указании на НЕОБХОДИМОСТЬ ПРИСУТСТВИЯ! Надо и это мне тоже учесть... таааак.

http://alenacpp.blogspot.com/2006/04/volatile.html

Это сообщение отредактировал(а) NYX - 16.7.2012, 01:05
--------------------
'long long long' is too long for GC
PM   Вверх
Dem_max
Дата 16.7.2012, 05:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 4
Всего: 39



Цитата

Это был на вопрос участника выше: что делать в бесконечном цикле. 
Проверять эту атомарную переменную и завершать выполнение цикла


Бесконечный цикл это к примеру. Ну в коде с большой вероятностью может присутствовать такая строчка
WaitForSingleObject(hHandle, INFINITE);

Ну и если событие по каким то причинам никогда не наступит, то все поток весит. Никакие флаги не спасут отца русской демократии.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Randajad
Дата 16.7.2012, 10:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Говнокодить не надо, чтобы оно по каким-то причинам не наступило. smile

Добавлено через 25 секунд
Это к сабжу уже не относится, кстати. smile
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

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

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

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

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


 




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


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

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