Strona 1 z 1
[+] Rzutowanie C++ (pthread)
: 26 lutego 2010, 20:14
autor: grum
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ę.
Kod: Zaznacz cały
pthread_create(&thread_id , NULL, MagicznaKlasa->MagicznaMetoda ,NULL);
dla poniższego przykładu działa
Kod: Zaznacz cały
pthread_create(&thread_id , NULL, MagicznaFunkcja ,NULL);
Przy pierwszym przykładzie mam następujący błąd
Kod: Zaznacz cały
Command.cpp:34: error: argument of type ‘void* (Server: :) (void*)’ does not match ‘void* (*)(void*)’
: 27 lutego 2010, 00:40
autor: godlark
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?
: 27 lutego 2010, 16:15
autor: grum
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.
: 27 lutego 2010, 20:09
autor: godlark
A skopiuj i pokaż część kodu za to odpowiedzialną.
: 28 lutego 2010, 12:17
autor: grum
Program jest bardzo długi, dlatego wstawiam tylko najważniejsze fragmenty:
Kod: Zaznacz cały
//...
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
//...
}
//..
}
: 28 lutego 2010, 14:11
autor: godlark
Kod: Zaznacz cały
#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ć.
: 10 marca 2010, 21:20
autor: Wielkie G
@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:
Kod: Zaznacz cały
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.