[C++] Wątek na metodzie NIE-statycznej


(Przemekbaranowski) #1

Witam!

Potrzebuję utworzyć nowy wątek w swojej metodzie. wydawało by się, nic trudnego, ale jako procedurę obsługi wątku muszę użyć metody nie statycznej.

używam CreateThread , projekt się kompiluje, ale procedura obsługi wątku wykonuje się do momentu użycia pierwszego niestatycznego atrybutu.

Czy istnieje sposób, by na to zaradzić? może jakaś inna funkcja do tworzenia wątku?


(Fiołek) #2

To "wina" języka - C++ sam w sobie nie obsługuje tzw. delegatów. Ale da się to dość prosto obejść. Użyj metody statycznej, jako parametr wątku podaj wskaźnik na żądany obiekt i z poziomu tej metody wywołaj metodę obiektu.

class Thread

{

public: void Run() {/*...*/}

};


void ThreadMain(LPVOID param)

{

((Thread*)param)->Run();

}


//...

Thread th;

CreateThread(NULL, 0, ThreadMain, (LPVOID)&th, 0, NULL);

(Przemekbaranowski) #3

sprytne:D

dzięki;)


(Ryan) #4

Tylko bądź świadom tego, że zaproponowany cast przestanie działać jeśli użyjesz bardziej złożonego dziedziczenia i znaczenie zacznie mieć budowa vtable. Generalnie jedyną uniwersalną odpowiedzią na Twój problem jest: nie rób tego. Nie rób i tyle.


([alex]) #5
class Thread

  {

   public: 

   void Run() {/*...*/}

   void Start() { CreateThread(0,0,SRun,reinterpret_cast<(LPVOID)>this,0,0);

   private:

   static void SRun(LPVOID param) { reinterpret_cast(param)->Run(); }

  };

I masz w nosie vtable.


(Fiołek) #6

Mógłbyś rozwinąć, jak na to wpływa vtable? Czy może masz na myśli wielodziedziczenie?

@[alex]: AFAICR reinterpreted_cast działa identycznie jak rzutowanie C-style, tylko trzeba się więcej napisać.

EDIT:

@down: dzięki za wyjaśnienie.


(Ryan) #7

To jest praktycznie to samo. A nie należy używać z powodów opisanych w części 33. C++ FAQ, sugeruję przeczytać. Jest tam też obejście dla wywołań, które oczekują callbacka i dają opcjonalny parametr. Krótka odpowiedź dla niecierpliwych to: standard określa takie wywołanie jako undefined, co znaczy, że do twórców kompilatora należy ustalenie czy działa, jak i kiedy. Mogą to implementować jak chcą i robią tak. I mogą działanie podobnego casta zmienić kiedy chcą, w końcu zachowanie nie jest częścią standardu. Szczególnie zachowanie przestaje być przewidywalne, gdy funkcja jest wirtualna. Albo miała słowo kluczowe virtual w klasie bazowej a w potomnej już nie. Czasem przy większej złożoności kodu nie uzyskujemy oczekiwanego rezultatu, czasem całkiem szybko. Jest jeszcze kilka pobocznych powodów. Nie należy tak robić i już.


([alex]) #8

Nie myl powinno działać identycznie z działa identycznie.

Pamiętam 3 dni debugowania kodu kiedy to rzutowanie c-style na void* zmieniało mi wskaźnik na klasę bazową, więc po powrotnym rzutowaniu program zaczynał się sypać.


(Ryan) #9

Zgłosiłeś błąd w kompilatorze?