|
[+] Rzutowanie C++ (pthread)
grum - 26-02-2010 20:14
Piszę taki programik i utknąłem przy tworzeniu nowego wątku. Wszystko jest pięknie jeśli wywołuje funkcję, sprawa się natomiast komplikuje jeśli chce wywołać metodę.
pthread_create(&thread_id , NULL, MagicznaKlasa->MagicznaMetoda ,NULL);
dla poniższego przykładu działa
pthread_create(&thread_id , NULL, MagicznaFunkcja ,NULL);
Przy pierwszym przykładzie mam następujący błąd
Command.cpp:34: error: argument of type ‘void* (Server::)(void*)’ does not match ‘void* (*)(void*)’
godlark - 27-02-2010 00:40
Zamiast „->” powinno być „::”, powinno zadziałać. Tak poza tematem, gdzie podajesz jakiś obiekt typu MagicznaKlasa, bo to tak na niczym się*nie wywoła, chyba, że statyczna?
grum - 27-02-2010 16:15
To nie jest metoda statyczna i raczej bardzo ciężko będzie ją przerobić na statyczną. Spróbowałem tak zrobić jak napisałeś, ale nie działa, zresztą spodziewałem się tego.
godlark - 27-02-2010 20:09
A skopiuj i pokaż część kodu za to odpowiedzialną.
grum - 28-02-2010 12:17
Program jest bardzo długi, dlatego wstawiam tylko najważniejsze fragmenty:
//... class MagicznaKlasa { public: void *MagicznaMetoda (void*){ // operacje polegające na odczytywaniu wartość zmiennych przetworzeniu ich i wysłaniu ich do innego komutera } };
int main (int argc, char *argv[]) { //... MagicznaKlasa *MojaMagicznaKlasa = new MagicznaKlasa(argumenty);
for (;;) { //... MojaMagicznaKlasa->AkceptujNowego(); pthread_create(&thread_id , NULL, MojaMagicznaKlasa->MagicznaMetoda,NULL); // Tutaj jest błąd //... } //.. }
godlark - 28-02-2010 14:11
#include <iostream>
using namespace std;
void* pthread_create(void* (*start_routine)(void*), void *arg) { (*start_routine)(arg); }
class MagicznaKlasa { public: void* MagicznaMetoda (void *something){ cout << "something" << endl; } };
struct TwoVoidPointer { void *one; void *two; };
void* pomoc(void *arg) { TwoVoidPointer *arguments = static_cast<TwoVoidPointer*>(arg); MagicznaKlasa *m = static_cast<MagicznaKlasa*>(arguments->one); return m->MagicznaMetoda(arguments->two); }
int main (int argc, char *argv[]) { MagicznaKlasa *MojaMagicznaKlasa = new MagicznaKlasa(); TwoVoidPointer *data = new TwoVoidPointer; data->one = static_cast<void*>(MojaMagicznaKlasa); data->two = NULL; //coś do przekazania MagicznaMetoda pthread_create(&pomoc, data); }
Zrobiłem sobie funkcję pthread_create, której działanie jest podobne do oryginalnej, tzn. wywołuje podaną jej funkcję z argumentem podanym na samym końcu. Kod sobie powininien przerobić.
Wielkie G - 10-03-2010 21:20
@grum: Funkcja pthread_create oczekuje wskaźnika na *funkcję*. Możesz więc przekazać tam tylko i wyłącznie funkcję (ew. metodę statyczną). Wskaźnik na metodę nie ma wiele wspólnego ze wskaźnikiem na funkcję (może tylko pod względem implementacyjnym). Aby wywołać metodę ze wskaźnika na metodę potrzebujesz obiektu, co w ogóle dyskwalifikuje jego użycie w pthread_create. Rozwiązanie: pthread_create przyjmuje jako ostatni argument wskaźnik na void (w nomenklaturze C jest to tzw. wskaźnik na wszystko). Zrzutuj wskaźnik na obiekt klasy MagicznaKlasa do void* (reinterpret_cast<void*> (...)) i daj jako ostatni argument pthread_create. Zamiast MagicznaMetoda, wstaw jakąś zwykłą funkcję, która zrzutuje void* z powrotem na MagicznaKlasa* i wywoła odpowiednią metodę. Prościej:
void* MagicznaKlasa_MagicznaMetoda_helper(void* ptr) { MagicznaKlasa* obj = reinterpret_cast<MagicznaKlasa*> (ptr); return obj->MagicznaMetoda(); }
...
pthread_create(&thread_id, 0, &MagicznaKlasa_MagicznaMetoda_helper, reinterpret_cast<void*> (MojaMagicznaKlasa));
PS. Ja preferuję użycie 0 ponad NULL - NULL to taka pozostałość z języka C, która nic nie wnosi.
zanotowane.pldoc.pisz.plpdf.pisz.plminister.pev.pl
|