Kód Win thread
Z CHWiki
Obsah |
[editovat] Vlákna EXT knihovny
Šablony win::thread a win::threadc zapouzdřují tvorbu a správu vláken do jednoduchých objektů se zachováním objektové sémantiky. Tedy vlákno je považováno za objekt, vytváří se při konstrukci nosného objektu a zaniká dříve nebo společně s ním. Zaniká-li objekt za běhu vlákna, je destruktor pozdržen do doby skončení vlákna. Pro práci s vláknem je možno použít několik metod popsaných dále.
[editovat] win::thread
Tuto šablonu použijte k vytvoření vlákna, které provede kód globální funkce nebo statické metody. Funkce musí mít následující signaturu:
int procedure (void *) {
// ...
return 0;
};
Syntaxe k vytvoření vlákna je dvojí, s parametrem nebo bez:
win::thread <procedure> thread; win::thread <procedure> thread (ptr);
Parametr ptr je ukazatel typu void * a specifikuje parametr, který se předává vláknu. Není-li uveden, předává se NULL.
[editovat] win::threadc
Tuto šablonu použijte k vytvoření vlákna, které provede kód metody v kontextu objektu. Metoda musí mít následující signaturu:
struct Class {
int Method (void *) {
// ...
return 1;
};
};
K vytvoření vlákna je možné použít jeden z následujícíh zápisů
win::thread <Class, &Class::Method> t2; win::thread <Class, &Class::Method> t2 (ptr); win::thread <Class, &Class::Method> t2 (object); win::thread <Class, &Class::Method> t2 (object, ptr);
Podobně jako u win::threadc, je parametr ptr ukazatel typu void * a specifikuje parametr, který se předává vláknu. Není-li uveden, předává se NULL.
Je-li předán objekt (referencí), metoda v novém vlákně se volá v kontextu tohoto objektu. Není-li žádný objekt předán, vytvoří se jeden dočasný v kontextu nového vlákna a zaniká po skončí metody společně s vláknem.
[editovat] Metody
Obě výše zmíněné šablony vystavují tyto metody:
- bool running () const throw ();
- vrací true, pokud vlákno stále běží; false pokud již skončilo
- bool failed () const throw ();
- vrací true, pokud vlákno skončilo nezachycenou výjimkou, jinak false
- int result () const throw ();
- vrací návratovou hodnotu vlákna, pokud vlákno stále běží vrátí 259 (Windowsovská konstanta STILL_ACTIVE)
- void wait () const throw ();
- pozdrží provádění do momentu skončení vlákna
- pokud vlákno už neběží, vrátí okamžitě
[editovat] Do dalších verzí
- win::threadc rozšířit o možnost předávání konstantních referencí na objekt (omezení na vytváření vláken jen z konstantních metod)
- doplnit více metod (minimálně id vlákna)
[editovat] Zdrojové kódy
[thread.hpp]
#ifndef WIN_THREAD_HPP
#define WIN_THREAD_HPP
namespace win {
// thread_base, bazova trida pro thread a threadc
class thread_base {
private:
class implementation;
volatile implementation * pimpl;
protected:
thread_base (int (*) (void *), void *);
~thread_base () throw ();
public:
bool running () const throw ();
bool failed () const throw ();
int result () const throw ();
void wait () const throw ();
};
// thread <function> t1;
// thread <function> t1 (void *);
// - int function (void *);
template <int (*P) (void *)>
class thread : private thread_base {
public:
thread (void * = 0);
public:
using thread_base::running;
using thread_base::failed;
using thread_base::result;
using thread_base::wait;
};
// thread <Class, &Class::Method> t2;
// thread <Class, &Class::Method> t2 (void *);
// thread <Class, &Class::Method> t2 (object);
// thread <Class, &Class::Method> t2 (object, void *);
template <typename C, int (C::*P) (void *)>
class threadc : private thread_base {
private:
C * const object;
const bool owned;
void * arg;
static int caller (void *);
public:
threadc (void * = 0);
threadc (C & c, void * = 0);
~threadc () throw ();
public:
using thread_base::running;
using thread_base::failed;
using thread_base::result;
using thread_base::wait;
};
};
#include "thread.tcc"
#endif
[thread.tcc]
#ifndef WIN_THREAD_TCC
#define WIN_THREAD_TCC
template <int (* ptr) (void *)>
win::thread <ptr> ::thread (void * arg)
: win::thread_base (ptr, arg) {};
template <typename C, int (C::*ptr) (void *)>
win::threadc <C, ptr> ::threadc (void * _arg)
: win::thread_base (caller, this),
object (new C), owned (true), arg (_arg) {};
template <typename C, int (C::*ptr) (void *)>
win::threadc <C, ptr> ::threadc (C & c, void * _arg)
: win::thread_base (caller, this),
object (&c), owned (false), arg (_arg) {};
template <typename C, int (C::*ptr) (void *)>
win::threadc <C, ptr> ::~threadc () throw () {
this->wait ();
if (this->owned)
delete this->object;
};
template <typename C, int (C::*ptr) (void *)>
int win::threadc <C, ptr> ::caller (void * param) {
win::threadc <C, ptr> * self =
reinterpret_cast <win::threadc <C, ptr> *> (param);
return (self->object->*ptr) (self->arg);
};
#endif
[thread.cpp]
#include "thread.hpp"
#include <windows.h>
class win::thread_base::implementation {
private:
int (* ptr) (void *);
void * arg;
public:
bool failed;
HANDLE hThread;
DWORD dwThreadId;
private:
static DWORD WINAPI procedure (LPVOID);
public:
implementation (int (*) (void *), void *);
};
win::thread_base::implementation::implementation (int (* _ptr) (void *),
void * _arg)
: ptr (_ptr),
arg (_arg),
failed (false),
hThread (CreateThread (NULL, 0, procedure,
this, CREATE_SUSPENDED, &this->dwThreadId)) {
ResumeThread (this->hThread);
return;
};
DWORD WINAPI win::thread_base::implementation::procedure (LPVOID param) {
volatile win::thread_base::implementation * self =
reinterpret_cast <volatile win::thread_base::implementation *> (param);
try {
return self->ptr (self->arg);
} catch (...) {
self->failed = true;
return (DWORD) -1;
};
};
win::thread_base::thread_base (int (* ptr) (void *), void * arg)
: pimpl (new implementation (ptr, arg)) {};
win::thread_base::~thread_base () throw () {
this->wait ();
delete this->pimpl;
this->pimpl = NULL;
return;
};
int win::thread_base::result () const throw () {
DWORD dwResult (0);
GetExitCodeThread (this->pimpl->hThread, &dwResult);
return dwResult;
};
bool win::thread_base::running () const throw () {
return WaitForSingleObject (this->pimpl->hThread, 0) != WAIT_OBJECT_0;
};
bool win::thread_base::failed () const throw () {
return this->pimpl->failed;
};
void win::thread_base::wait () const throw () {
WaitForSingleObject (this->pimpl->hThread, INFINITE);
return;
};
