Класс обертка для потока(Thread)
От: Gorik Россия  
Дата: 28.08.02 13:38
Оценка:
Здраствуйте, уважаемые жители RSDN.
Представляю вашему вниманию класс который разработал год назад. Он до сих пор не потерял своей актуальности, и думаю еще долго не потеряет.
Кстати переделывание старых проектов для работы через этот класс занимало минимум усилий. Но, возможно, это оттого, что я автор. Надеюсь мне все же удастся донести до общественности основные идеи.

К идее создания этого класса меня привела досадная неполноценность ряда операционных систем от одной мелкомягкой компании. Фукция TerminateThread появилась только в Win2k, да и то она убивает поток, а выделенные ресурсы так и остаются, до смерти самого процесса. Хочется чего-нибудь краткого и мощного. Это и было сделано.


// thread.h: interface for the threadable class.
//
// Design by Petrov Evgeniy with Todyshev Sergey 2001
//////////////////////////////////////////////////////////////////////

#ifndef _THREAD_INC_HEADER
#define _THREAD_INC_HEADER

/*concept:
  Испокон веков поток реализовывался одной функцие примерно следующего вида.

  UINT ThreadFunc(LPVOID pData)
  {
     ...
     Инициализация - в полном смысле этого слова
     ...
     while(need_continue)
     {
         ....
         Поток что-то делает
         ....
     }
     ...
     Завершение (всякого рода освобождение ресурсов)
     ...
     return _retval;
  }

  Естественно различные задачи требуют различной реализации, данный подход применим лишь
  для самой популярной модели.

  И, коль скоро удалось применить декомпозицию к такой сущности как Поток, то логично 
  агрегировать эти части в класс, что и сделано ниже.

  Инициализация.
  Шаг.
  Завершение.

  Имеено на эти части можно разбить любой нормальный поток. 
*/

/*
  Зачем все это нужно?
  Обычный поток недостаточно управляем. Поскольку все собрано в одной функции, нет 
  возможности манипулировать отдельными частями. Предлагаемый класс достаточно легко и
  интуитивно позволяет манипулировать потоком.
*/


#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#pragma warning(disable:4786)
#pragma warning(disable:4800)
#include "semaphore.h"
#include <map>
using namespace std;



// Флаги состояния потока
#define _THREAD_STATUS_UNKNOWN        0x000

#define _THREAD_STATUS_STARTED        0x001
// Поток в работе (т.е в основном цикле)
#define _THREAD_STATUS_SUSPENDED    0x002
// Поток приостановлен
#define _THREAD_STATUS_FINISHING    0x004
// Идет завершение 
#define _THREAD_STATUS_STARTING        0x008
// Идет инициализация


class cThread: public semaphore
{
public:

    // Инициализация данных, для данного экземпляра потока. 
    //Реализуется соответствующим классом потомком.
    virtual bool Init()throw(){return true;}
    // Один шаг цикла.
    virtual bool Step() throw() = 0;
    //  Завершение.
    virtual int Finish(){return 0;};

private:
    DWORD dwThreadId;
    HANDLE hThread;
    int nSleepTime;
    int nStatus;
private:
    static unsigned long __stdcall Run(void* buf);
private:
    //Блок управления флагами потока
    void Finishing(){ nStatus |= _THREAD_STATUS_FINISHING    ; }
    void Starting(){ nStatus |= _THREAD_STATUS_STARTING    ; }
    void Suspended(){ nStatus |= _THREAD_STATUS_SUSPENDED; }
    void Resumed(){ nStatus &= ~_THREAD_STATUS_SUSPENDED; }
    void Started(){ nStatus |= _THREAD_STATUS_STARTED; }
    void Stoped(){ nStatus &= ~_THREAD_STATUS_STARTED; }
public:
    cThread():dwThreadId(0),hThread(0),nStatus(_THREAD_STATUS_UNKNOWN)
    {
        SetDelay();
    }
public:

    /* Блок управления потоком*/
    // Начать поток
    virtual int Start(BOOL bSuspended=FALSE, int StackSize=0);
    // Приостановить поток
    int Suspend();
    // Разбудить поток
    virtual int Resume();
    // Остановить поток
    virtual int Stop();

public:
    int SetDelay(int dt=50){ return nSleepTime = dt; }
    int GetDelay() const {return nSleepTime;}
    int SetPriority(int prior) { return IsStarted()?SetThreadPriority(hThread,prior):THREAD_PRIORITY_ERROR_RETURN;}
    int GetPriority(int prior) const { return IsStarted()?GetThreadPriority(hThread):THREAD_PRIORITY_ERROR_RETURN;}
private:
    bool IsFinishing() const { return nStatus & _THREAD_STATUS_FINISHING; }
    bool IsStarting() const { return nStatus & _THREAD_STATUS_STARTING; }
public:
    bool IsSuspended() const { return nStatus & _THREAD_STATUS_SUSPENDED; }
    bool IsResumed() const { return !IsSuspended(); }
    bool IsStarted() const { return dwThreadId!=0&&hThread!=0&&(nStatus & _THREAD_STATUS_STARTED); }
    bool IsStoped() const { return !IsStarted(); }
};

#endif // _THREAD_INC_HEADER


А вот реализация.

// thread.cpp: implementation of the threadable class.
//
// Design by Petrov Evgeniy with Todyshev Sergey 2001
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "thread.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

unsigned long cThread::Run(void* buf)
{
    cThread * pThread = (cThread*)buf;
    if(pThread->Init())
    {
        pThread->nStatus=_THREAD_STATUS_STARTED;
        while(!pThread->IsFinishing())
        {
            if(!pThread->Step())
                break;
            Sleep(pThread->GetDelay());
        }
        pThread->Finish();
    }
    pThread->nStatus=_THREAD_STATUS_UNKNOWN;
    return 0;
}
int cThread::Start(BOOL bSuspended, int StackSize)
{
    if(IsStarted())
        return false;
    hThread=CreateThread(NULL,StackSize,Run,this,bSuspended?CREATE_SUSPENDED:0,&dwThreadId);
    if(hThread)
    {
        if(bSuspended)
        {
            Suspended();
            return true;
        }
        Starting();
        while(IsStarting())
            Sleep(70);
        return true;
    }
    else
    {
        dwThreadId = 0;
        nStatus=_THREAD_STATUS_UNKNOWN;
        return false;
    }
}
int cThread::Stop()
{
    if(IsStoped())return false;
    Resume();
    Finishing();
    while(IsStarted()&&IsFinishing())
        Sleep(70);
    nStatus = _THREAD_STATUS_UNKNOWN;
    return true;
}

int cThread::Suspend()
{
    if(IsSuspended()||IsStoped()) return false;
    if(SuspendThread(hThread)==-1)
        return false;
    Suspended();
    return true;
}
int cThread::Resume()
{
    if(IsResumed()||IsStoped()) return false;
    if(ResumeThread(hThread)==-1)
        return false;
    Resumed();
    return true;
}


Пользуйтесь.
Возможно я переоцениваю важность данной идеи. Но мне эти строки спасли много нервов.

Чтобы пользоваться достаточно пронаследоваться и реализовать соответствующие члены-функции.
Фарш невозможно провернуть назад (с)Второе начало термодинамики
Re: Класс обертка для потока(Thread)
От: Sergey Россия  
Дата: 28.08.02 13:53
Оценка:
Здравствуйте Gorik, Вы писали:

G>Здраствуйте, уважаемые жители RSDN.

G>Представляю вашему вниманию класс который разработал год назад. Он до сих пор не потерял своей актуальности, и думаю еще долго не потеряет.
G>Кстати переделывание старых проектов для работы через этот класс занимало минимум усилий. Но, возможно, это оттого, что я автор. Надеюсь мне все же удастся донести до общественности основные идеи.

G>К идее создания этого класса меня привела досадная неполноценность ряда операционных систем от одной мелкомягкой компании. Фукция TerminateThread появилась только в Win2k, да и то она убивает поток, а выделенные ресурсы так и остаются, до смерти самого процесса.


Откуда дровишки? TerminateThread есть и в NT, и в Win95, хотя пользоваться ей и вправду без крайней необходимости не стоит.

G>Хочется чего-нибудь краткого и мощного. Это и было сделано.



G>
Код поскипан.
G>


G>Пользуйтесь.


Рановато пользоваться — кто CloseHandle(hThread) делать будет?
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: Класс обертка для потока(Thread)
От: Аноним  
Дата: 28.08.02 17:10
Оценка:
Здравствуйте Gorik, Вы писали:


G>К идее создания этого класса меня привела досадная неполноценность ряда операционных систем от одной мелкомягкой компании. Фукция TerminateThread появилась только в Win2k, да и то она убивает поток, а выделенные ресурсы так и остаются, до смерти самого процесса. Хочется чего-нибудь краткого и мощного. Это и было сделано.


И какие-же ресурсы не убиваются? Все ресурсы из стека потока уничтожаются, но в классах C++ не вызываются деструкторы ну и не делаются разные там сохранения данных и проч. Но Ваш класс этого тоже не делает. Кроме того, так как поток создается с помощью CreateThread не выполняется инициализирующий код для рантайма языка С++.
Ну и завершить поток с помощью TerminateThread появилась еще в Win95.

.....
G> while(IsStarting())
G> Sleep(70);
а почему не использовать еvent'ы? Вроде бы и логичнее, и ресурсов процессора будет есть меньше?
....
Re[2]: Класс обертка для потока(Thread)
От: Gorik Россия  
Дата: 28.08.02 17:34
Оценка:
Здравствуйте Sergey, Вы писали:
S>Рановато пользоваться — кто CloseHandle(hThread) делать будет?
Простите великодушно за темноту и невежество. Но разве при выходе из потоковой функции хендл потока и все с ним связанное не уничтожается?
Фарш невозможно провернуть назад (с)Второе начало термодинамики
Re[3]: Класс обертка для потока(Thread)
От: Аноним  
Дата: 28.08.02 17:49
Оценка:
Здравствуйте Gorik, Вы писали:

G>Здравствуйте Sergey, Вы писали:

S>>Рановато пользоваться — кто CloseHandle(hThread) делать будет?
G>Простите великодушно за темноту и невежество. Но разве при выходе из потоковой функции хендл потока и все с ним связанное не уничтожается?

Хендл не уничтожится пока не вызвать CloseHandle. А внутренние структуры ядра будут жить, пока есть хотябы один открытый хендл на поток.
Собственно по этому хендлу можно проверть, завершился поток или нет фунцией WaitForSingleObject
Re[2]: Класс обертка для потока(Thread)
От: Gorik Россия  
Дата: 28.08.02 17:53
Оценка:
Здравствуйте Аноним, Вы писали:
G>>К идее создания этого класса меня привела досадная неполноценность ряда операционных систем от одной мелкомягкой компании. Фукция TerminateThread появилась только в Win2k, да и то она убивает поток, а выделенные ресурсы так и остаются, до смерти самого процесса. Хочется чего-нибудь краткого и мощного. Это и было сделано.

А>И какие-же ресурсы не убиваются? Все ресурсы из стека потока уничтожаются, но в классах C++ не вызываются деструкторы ну и не делаются разные там сохранения данных и проч. Но Ваш класс этого тоже не делает. Кроме того, так как поток создается с помощью CreateThread не выполняется инициализирующий код для рантайма языка С++.

Ресурсами я называю выделенную память в куче, открытые файлы, хендлы и т.п.
Мой класс ничего не делает, он базовый. Вы его наследуйте и переопределяйте методы Init и Finish, а в них уже инстанциируете, всю необходимую функциональность.

А>Ну и завершить поток с помощью TerminateThread появилась еще в Win95.

Простите, был дезинформирован.

А>.....

G>> while(IsStarting())
G>> Sleep(70);
А> а почему не использовать еvent'ы? Вроде бы и логичнее, и ресурсов процессора будет есть меньше?
А>....
Это уже детали реализации, Я-то пытался продвинуть концепцию. Но вариант интересный, я попробуй.

Тут вообще можно много нарасширять по теме синхронизации.
Фарш невозможно провернуть назад (с)Второе начало термодинамики
Re[3]: Класс обертка для потока(Thread)
От: Аноним  
Дата: 28.08.02 18:02
Оценка:
Здравствуйте Gorik

Ну может я туплю ;) Но после создания потока методы Init и Finish вызываются из него же. Значит, если поток завершить TerminateThread'ом или исключением, то никакой деинициализации не произойдет.
Re[4]: Класс обертка для потока(Thread)
От: Gorik Россия  
Дата: 28.08.02 18:20
Оценка:
Здравствуйте Аноним, Вы писали:

А>Ну может я туплю Но после создания потока методы Init и Finish вызываются из него же. Значит, если поток завершить TerminateThread'ом или исключением, то никакой деинициализации не произойдет.


Я предлагал модель. В рамках этой модели, поток завершается метедом Stop :-E
Фарш невозможно провернуть назад (с)Второе начало термодинамики
Re[2]: Класс обертка для потока(Thread)
От: Sergey Россия  
Дата: 29.08.02 09:28
Оценка:
Здравствуйте Аноним, Вы писали:

G>>К идее создания этого класса меня привела досадная неполноценность ряда операционных систем от одной мелкомягкой компании. Фукция TerminateThread появилась только в Win2k, да и то она убивает поток, а выделенные ресурсы так и остаются, до смерти самого процесса. Хочется чего-нибудь краткого и мощного. Это и было сделано.


А>И какие-же ресурсы не убиваются?


А слабо в MSDN заглянуть:

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. 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 executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.

Че, этих проблем мало?

А>Все ресурсы из стека потока уничтожаются, но в классах C++ не вызываются деструкторы ну и не делаются разные там сохранения данных и проч. Но Ваш класс этого тоже не делает. Кроме того, так как поток создается с помощью CreateThread не выполняется инициализирующий код для рантайма языка С++.


А>Ну и завершить поток с помощью TerminateThread появилась еще в Win95.


А>.....

G>> while(IsStarting())
G>> Sleep(70);
А> а почему не использовать еvent'ы? Вроде бы и логичнее, и ресурсов процессора будет есть меньше?

Если Init() не слишком тормозной (а он обязан быть быстрым, иначе этот класс вообще никуда не годиться), этот цикл вообще исполняться не будет. В крайнем случае, пару/тройку раз выполнится — это куда дешевле, чем создавать объект ядра.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.