Wywołanie metody z innej klasy, wykorzystanie wątków

0

Mam klasę główną, która powiedzmy pełni rolę takiego nadzorcy. Inne klasy to są moduły, które chciałbym móc uruchamiać z klasy głównej w wątkach. (modułów jest kilka)
Tworzę w klasie głównej metodę start w której wywołuję na rzecz obiektu klasy FirstModule jej metodę start() w której chcę odpalić metodę receive() z FirstModule.

class Main() {
public:

    Main() {}

    virtual ~Main(){}

    void start() {
        first->start();
    }

private:
    FirstModule *first;

};

class FirstModule() {
public:

    FirstModule() {
    }

    virtual ~FirstModule(){}

    void start() {
        std::thread(&FirstModule::receive, this);
        first.join();
    }

    void receive() {
        //...
    }
};

Jak poprawnie to zrobić i czy:

    std::thread(&FirstModule::receive, this);

jest poprawne? Czy wskaźnik this będzie wskazywał na odpowiedni obiekt, bo obecnie leci mi Segmenation Fault.

0

Hmm...

class FirstModule() { };

to jakaś nowość. Może powinieneś powrócić do nauki programowania obiektowego, bo jakoś słabo widzę.
Pomijając już nawet fakt jak to ma się skompilować, to co w FirstModule::start() robi to: first.join(); Zapewne chodziło ci o coś innego. Otóż ta linia:

std::thread(&FirstModule::receive, this);

pewnie miała wyglądać tak: std::thread first(&FirstModule::receive, this);

0

Pisałem to z głowy w drodze bez dostępu do kompilatora, bardziej chodziło mi o koncepcję jak rozwiązać coś takiego jak potrzebuję, nie wklejałem rzeczywistego kodu tylko przykładowy. Faktycznie () za nazwą klasy mi się gdzieś wkradły przez przypadek.

class Main {
public:
 
    Main() {}
 
    virtual ~Main(){}
 
    void start() {
        first->start();
    }
 
private:
    FirstModule *first;
 
};
 
class FirstModule {
public:
 
    FirstModule() {
    }
 
    virtual ~FirstModule(){}
 
    void start() {
        std::thread first(&FirstModule::receive, this);
        first.join();
    }
 
    void receive() {
        //...
    }
};

Wywołanie:

int main(){
       Main foo;
       foo.start();
}

Całość powinna wyglądać jak powyżej. Rozumiem, że znalazłeś jakieś literówki, a wiesz może w jaki sposób rozwiązać coś takiego jak potrzebuję i opisałem? Może kompletnie źle myślę i warto podejść do tego inaczej, nie chcę gotowca, chciałbym po prostu rady i nakierowania. Tyle.

1

No i tutaj są już niewybaczalne błędy, za które będę bił.
Popatrz, że masz wskaźnik FirstModule *first; w Main i w konstruktorze nic z nim nie robisz. A co to znaczy? A mogą być tam śmieci, wskaźnik który jest dobry albo zero, albo inna wartość. A później wołasz metodę start z Main która odnosi się do tego wskaźnika. Do którego nie ma przypisanego obiektu. Aczkolwiek z powodu budowy metod w klasach w kodzie maszynowym odpali ci się ta metoda, tylko, że this może być wszystkim. std::thread first(&FirstModule::receive, this); tak na prawdę możesz przypisywać dowolną wartość do drugiego argumentu, bo this tutaj to czysty undefined behavior. A tym samym kiedy wywołasz join() to już się wszystko sypie bo w metodzie receive this wskazuje na zero albo na inne cuda. Powrót do kursów chyba trzeba zrobić.

0

@mwl4 wyjaśnił już dlaczego dostajesz segfault. Abstrahując od tego wyjaśnij co chcesz zamodelować, bo uruchamianie osobnych wątków dla każdego modułu wydaje się być bardzo słabym pomysłem. Jeśli chcesz rozdzielać zadania do wykonania między wątkami to "użyj" puli wątków. Jeśli chcesz uzyskać coś w rodzaju zapytanie - odpowiedź to skorzystaj z std::future i std::promise. W każdym razie bez opisania dokładniej problemu ciężko znacząco zasugerować "poprawne" rozwiązanie.

0

@mwl4 dzięki za odpowiedź.

@Satirev
Ok powiedzmy, że mam kilka urządzeń, które się ze sobą komunikują i razem stanowią całość jakiegoś systemu. Jest urządzenie główne, które pełni rolę zarządzającą, tzn. odbiera i wysyła dane do innych urządzeń, przetwarza je i w zależności od tego co dostanie wykonuje jakąś operację. Dodatkowo, urządzenie główne włącza inne moduły do pracy i ma możliwość kontrolować ich stan. Chcę zdekomponować jakoś całość. Mnie interesuje tylko to urządzenie główne. Chciałbym sobie rozdzielić logikę całości, tak by np. osobne klasy odpowiadały za dany podmoduł, a istniała klasa główna która to wszystko spaja.

0

Zatem chcesz tylko delegować zadania i mieć możliwość sprawdzenia stanu wykonania zadania (skończony/w trakcie/błąd). Moim zdaniem najlepiej do tego byłoby użyć std::future via np std::async [std::launch::async] (ale możesz też wykorzystać std::packaged_task lub w ostateczności wyciągać std::future z std::promise, który prześlesz do std::thread). W każdym razie mając już uruchomione zadanie możesz pobrać stan wykonania zadania poprzez std::future::wait_for(). Jeszcze inną opcją jest np. użycie proactor pattern z jakimś schedulerem. To ostatnie radziłbym zastosować wtedy, gdy zadań (wątków) może być dużo.

1 użytkowników online, w tym zalogowanych: 0, gości: 1