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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Непонятки с потоком 
:(
    Опции темы
zss
Дата 16.2.2006, 10:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



что-то никак не пойму где косяк smile

*.h
Код
/*----------------------------------------------------------------------------*/
/* THREAD.H                                                                   */
/*----------------------------------------------------------------------------*/
#ifndef _THREAD_H_
#define _THREAD_H_
/*----------------------------------------------------------------------------*/
#include <windows.h>
#include <process.h>
/*----------------------------------------------------------------------------*/
class CallerImpl {

    private :
        CallerImpl (const CallerImpl&);
        CallerImpl& operator = (const CallerImpl&);

    protected :
        void *arg_;

    public :
        explicit CallerImpl () : arg_ (NULL) {;}
        virtual ~CallerImpl () {;}
        virtual unsigned Call(void) const = 0;

};
/*----------------------------------------------------------------------------*/
class StaticCaller : public CallerImpl {

    private :
        typedef unsigned (*Func)(void *);
        Func func_;

        StaticCaller (const StaticCaller&);
        StaticCaller& operator = (const StaticCaller&);

        virtual unsigned Call (void) const { return func_ (arg_); }

    public :
        explicit StaticCaller (Func func, void *arg) : func_(func) { arg_ = arg; }
        virtual ~StaticCaller () {;}

};
/*----------------------------------------------------------------------------*/
template <class T>
class ClassCaller : public CallerImpl {

    private :
        typedef unsigned (T::*Func)(void *arg);
        T *obj_;
        Func func_;

        ClassCaller (const ClassCaller&);
        ClassCaller& operator = (const ClassCaller&);

        virtual unsigned Call (void) const { return ((obj_->*func_) (arg_)); }

    public :
        explicit ClassCaller (T *obj, Func func, void *arg) :
                         obj_(obj), func_(func) { arg_ = arg; }
        virtual ~ClassCaller () {;}


};

/*----------------------------------------------------------------------------*/
class Thread  {

    private:
     static const unsigned DEFAULT_TERMINATE_ = 100;
        HANDLE hThread_;
        unsigned threadID_;
        volatile bool autoTerminate_;
        volatile bool isSuspend_;

        Thread (const Thread&);
        Thread& operator = (const Thread&);

        static unsigned __stdcall ThreadFunc (void *arg){
            Thread *thread = reinterpret_cast<Thread *>(arg);
            thread->Execute();
            _endthreadex (0);
            return 0;
        }

        bool CreateThread (bool suspend);
        void DeleteThread (void);

    protected:
        volatile bool terminated_;
        virtual unsigned Execute(void) = 0;
        virtual bool OnStart    (void);
        virtual void OnStop     (void);
        virtual bool OnResume   (void);
        virtual bool OnSuspend  (void);
        virtual bool OnTerminate (unsigned waitTime);

    public:
        explicit Thread (bool suspend = true) : hThread_ (INVALID_HANDLE_VALUE),
                                             terminated_ (false),
                                                isSuspend_ (suspend),
                                                autoTerminate_(false) {
            if (!Thread::CreateThread(suspend)) throw "Ошибка создания потока";
        }

        virtual ~Thread () {
         if (!isSuspend_) {
             if (!autoTerminate_) OnStop();
                else DeleteThread();
            }
            else OnTerminate(DEFAULT_TERMINATE_);
     }

        unsigned GetID (void) const { return threadID_; }
        bool Start  (void) { return OnStart (); }
        bool Resume (void) { return OnResume (); }
        bool Suspend(void) { return OnSuspend (); }
     void SetAutoTerminate (bool terminate) { autoTerminate_ = terminate; }
        bool IsRun  (void) const { return (!isSuspend_); }

};
/*----------------------------------------------------------------------------*/
class MethodThread : public Thread {

    private:
        CallerImpl *caller_;

        MethodThread (const MethodThread&);
        MethodThread& operator = (const MethodThread&);

    protected:
        virtual unsigned Execute(void) { return caller_->Call(); }

    public:
        template <class T>
        explicit MethodThread (T *obj, unsigned (T::*Func)(void *),
                         void *arg = NULL) : caller_(NULL) {
            caller_ = new ClassCaller <T> (obj, Func, arg);
        }

        explicit MethodThread (unsigned (*Func)(void *), void *arg = NULL) :
                         caller_(NULL) {
            caller_ = new StaticCaller (Func, arg);
        }

        virtual ~MethodThread () { delete caller_; }

};
/*----------------------------------------------------------------------------*/
#endif
/*----------------------------------------------------------------------------*/


*.cpp
Код
/*----------------------------------------------------------------------------*/
/* THREAD.CPP                                                                 */
/*----------------------------------------------------------------------------*/
#define _THREAD_CPP_
/*----------------------------------------------------------------------------*/
#include "thread.h"
/*----------------------------------------------------------------------------*/
bool Thread::CreateThread (bool suspend){

    SECURITY_ATTRIBUTES  sa = { sizeof(SECURITY_ATTRIBUTES), 0, TRUE };
    hThread_ = (HANDLE)_beginthreadex (&sa, 0, ThreadFunc, this,
                                       suspend ? CREATE_SUSPENDED : 0, &threadID_);
    if (hThread_ == INVALID_HANDLE_VALUE){
        return false;
    }

    return true;
}
/*----------------------------------------------------------------------------*/
void Thread::DeleteThread (void){

    __try {
        if (hThread_ == INVALID_HANDLE_VALUE) return;
        CloseHandle(hThread_);
    }
    __finally {
        hThread_ = INVALID_HANDLE_VALUE;
    }

}
/*----------------------------------------------------------------------------*/
bool Thread::OnStart (void){

    if (!isSuspend_) return true;
    if (ResumeThread (hThread_) == 0xFFFFFFFF){
        return false;
    }

    isSuspend_ = false;
    return true;
}
/*----------------------------------------------------------------------------*/
void Thread::OnStop (void){

    __try {
        if (isSuspend_) return;
        terminated_ = true;
        WaitForSingleObject (hThread_, INFINITE);
    }
    __finally {
        DeleteThread();
    }
}
/*----------------------------------------------------------------------------*/
bool Thread::OnResume (void) {

    if (!isSuspend_) return true;
    if (ResumeThread (hThread_) == 0xFFFFFFFF){
        return false;
    }

    isSuspend_ = false;
    return true;
}
/*----------------------------------------------------------------------------*/
bool Thread::OnSuspend (void) {

    if (isSuspend_) return true;
    if (SuspendThread (hThread_) == 0xFFFFFFFF){
        return false;
    }

    isSuspend_ = true;
    return true;

}
/*----------------------------------------------------------------------------*/
bool Thread::OnTerminate(unsigned waitTime){

    __try {
        terminated_ = true;
        if (WaitForSingleObject (hThread_, waitTime) == WAIT_TIMEOUT){
            if (!TerminateThread (hThread_, FALSE)){
                return false;
            }
        }
    }
    __finally {
        DeleteThread();
    }
    return true;

}
/*----------------------------------------------------------------------------*/


и тогда если
Код
unsigned Thread (void *arg){
while(1){
   Sleep (100);
}
}

void main(void){
    for (int i=0; i < 10; i++){
        MethodThread thread (Thread);
        thread.SetAutoTerminate (true);
        thread.Start();
    }
}


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

Где косяк ?
PM MAIL ICQ   Вверх
threef
Дата 16.2.2006, 18:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 27.10.2005
Где: Запорожье

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



Я не знаю, чего ты хотел, может так ?

Код

 MethodThread *thread[10];
 for (int i=0; i < 10; i++)
    {
        thread[i]=new MethodThread(Thread);
        thread[i]->SetAutoTerminate (true);
        thread[i]->Start();
    }
 for (i=0; i < 10; i++)
    {
        delete thread[i];
    }
Код




Наверное, при попытке создать поток внутри цикла в локальной переменной у тебя уничтожается эта переменная, чему мешает и Sleep и WaitForSingleObject
PM MAIL   Вверх
zss
Дата 16.2.2006, 20:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(threef @ 16.2.2006, 18:58 Найти цитируемый пост)
Я не знаю, чего ты хотел, может так ?

да нет - именно локальный объект (у меня установлен AutoTerminate - тоесть поток
сам отомрет как только закончит выполнение)

ошибку подсказали - при вызове деструктора иничтожается объект
caller_. А когда поток запускается, то естественно бызывает caller_->Call()
для несуществующего объекта


но как это победить ? (я имею ввиду запрет вызова Call(), если объект убит)
ведь это статическая функция.

А как привязать к этому хозяйству синхронизацию - никак не пойму smile
PM MAIL ICQ   Вверх
threef
Дата 16.2.2006, 21:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 27.10.2005
Где: Запорожье

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



У меня синтаксис обьявления Thread не прошел, поэтому я
поменял:
Код

class Thread{
...
  static const unsigned DEFAULT_TERMINATE_ ;
...

и перенес в cpp:

Код


const unsigned Thread::DEFAULT_TERMINATE_ = 100;



Компилится и работает ok ms 6.0

PM MAIL   Вверх
zss
Дата 16.2.2006, 21:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



threef, это временный эфект (если ты конечно не через new создаешь объекты) - попробуй увеличь число циклов - рано или поздно должно слететь smile
Добавлено @ 22:00
Цитата(threef @ 16.2.2006, 21:44 Найти цитируемый пост)
У меня синтаксис обьявления Thread не прошел, поэтому я
поменял:

странно - стандарт С++ позволяет статически целочисленные константы инициализировать в заголовочном файле ...

Это сообщение отредактировал(а) zss - 16.2.2006, 22:01
PM MAIL ICQ   Вверх
threef
Дата 17.2.2006, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 27.10.2005
Где: Запорожье

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



Не полностью разобрал, потому как читать твою программу- одно удовольствие, не читать - другое. Судя по всему, главный поток процесса не дает возможности отработать новым потокам связывание с виртуальной таблицей. Может, до момента удаления обьекта стоит придержать главный поток Suspend-ом ? Потому как лечится просто :
Код

unsigned Thread (void *arg){
while(1){
       cout<<"What is the sens?\n";
       Sleep (100);
}
}
void main(void)
{
 for (int i=0; i < 100; i++)
    {
        MethodThread thread(Thread);
        thread.SetAutoTerminate (true);
        thread.Start();
        Sleep(0);
    }
}
 


Насчет синхронизации, попробовал привинтить критическую секцию к деструктору - не удалось smile
PM MAIL   Вверх
zss
Дата 17.2.2006, 12:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(threef @ 17.2.2006, 11:57 Найти цитируемый пост)
Насчет синхронизации, попробовал привинтить критическую секцию к деструктору - не удалось

я тоже пробова - не прокатило

придерживать поток как-то криво smile
PM MAIL ICQ   Вверх
threef
Дата 17.2.2006, 17:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 27.10.2005
Где: Запорожье

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



А в чем задача-то ?
PM MAIL   Вверх
Earnest
Дата 17.2.2006, 21:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

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



Если я правильно поняла, то в цикле
Код

for (int i=0; i < 100; i++)
    {
        MethodThread thread(Thread);
        thread.SetAutoTerminate (true);
        thread.Start();
    }

проблема в том, что локальная переменная может быть уничтожена раньше, чем поток на самом деле стартовал. Так? Тогда выход в том, чтобы не выходить их метода Start до того как стартует потоковая функция. Достигнуть этого просто: событие, которого ждешь в функции Start перед тем как выйти. А событие сигналится из функции потока - когда ей уже передано управление.
Достаточно частая ситуация, кстати: запускают поток и сразу начинают что-нибудь делать в основном, считая, что раз "start" вызван, то поток действительно стартовал...


--------------------
...
PM   Вверх
zss
Дата 17.2.2006, 23:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(Earnest @ 17.2.2006, 21:54 Найти цитируемый пост)
Тогда выход в том, чтобы не выходить их метода Start до того как стартует потоковая функция



даже если она стартует - это ничего не изменит. Потоковая функция может прерватся, в тот момент когда объект умрет - и если поток проснется - косяк.

На сколько я понял - если это объект поток - то он должен жить не менее чем сам поток.


Единственное что можно сделать - убивать объект из самого потока, но тогда нельзя самому вызывать деструктор (правда непонятно как это сделать smile)
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
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.0546 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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