[+] Rzutowanie C++ (pthread)

Potrzebujesz pomocy z C, C++, perl, python, itp.
grum

[+] Rzutowanie C++ (pthread)

Post 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*)’
Awatar użytkownika
godlark
Posty: 51
Rejestracja: 17 stycznia 2009, 14:33

Post 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?
grum

Post 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.
Awatar użytkownika
godlark
Posty: 51
Rejestracja: 17 stycznia 2009, 14:33

Post autor: godlark »

A skopiuj i pokaż część kodu za to odpowiedzialną.
grum

Post 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
   //...
   }
//..
}
Awatar użytkownika
godlark
Posty: 51
Rejestracja: 17 stycznia 2009, 14:33

Post 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ć.
Wielkie G
Posty: 10
Rejestracja: 23 października 2007, 14:05

Post 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.
ODPOWIEDZ