Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Непонятки с потоком


Автор: zss 16.2.2006, 10:51
что-то никак не пойму где косяк 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();
    }
}


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

Где косяк ?

Автор: threef 16.2.2006, 18:58
Я не знаю, чего ты хотел, может так ?

Код

 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

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

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

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


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

А как привязать к этому хозяйству синхронизацию - никак не пойму smile

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

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

и перенес в cpp:

Код


const unsigned Thread::DEFAULT_TERMINATE_ = 100;



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

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

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

Автор: threef 17.2.2006, 11:57
Не полностью разобрал, потому как читать твою программу- одно удовольствие, не читать - другое. Судя по всему, главный поток процесса не дает возможности отработать новым потокам связывание с виртуальной таблицей. Может, до момента удаления обьекта стоит придержать главный поток 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

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

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

придерживать поток как-то криво smile

Автор: threef 17.2.2006, 17:10
А в чем задача-то ?

Автор: Earnest 17.2.2006, 21:54
Если я правильно поняла, то в цикле
Код

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

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

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



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

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


Единственное что можно сделать - убивать объект из самого потока, но тогда нельзя самому вызывать деструктор (правда непонятно как это сделать smile)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)