Wątki w c++

0

Jest jakis sprytny pomysl aby przekazac do watku obkiekt klasu albo sam wskaznik do klasy??? (siedzie juz nad tym troche czasu i mam juz powoli dosc).

tworzac watek:
pthread_t tid;
pthread_create(&tid,NULL,funkcja,NULL);

jako 'funkcja' musze podac cos w stylu void()() wiec nie mam pomyslu jakby to ewentualni zrzutowac(o ile sie jakos da) na metode klasy np; MojaKlasa.mojafunkcja() w ktorej bylaby cala obsluga watku z dostepem do skladowych klasy. (bo o to mi glownie chodzi aby watek mial dostep do metod i skladowych klasy)

Jedyne co udalo mi sie zrobic to:

class MojaKlasa
{
  static void *Thread(void *arg);
}

int main()
{
  MojaKlasa client;
  pthread_t tid; 
  pthread_create(&tid,NULL,client.Thread,NULL);
}

I wszystko byloby cudowanie gdyby funkcja Thread nie byla static, bo przez to nie mam dostepu do niestatycznych skladowych i funkcji klasy...

(Na dzisiaj dosc.. ide spac... :P )

0

1) niestety, w tradycyjnym ujeciu posixowym, NIE MOZNA utworzyc watku opierajac sie na metodzie klasy - f.statyczna tak jak masz - moze byc

2) ostatni parametr w pthread_create to argument dla watku. zwroc uwage ze sygnetura funkcji watku jest void ()(void arg) -- czyli dostaje parametr void*

pomysl o:

class MojaKlasa
{
    static void Thread(void*arg)
    {
         MojaKlasa* ptr = static_cast<MojaKlasa*>(arg); //ew.dynamic i test czy ok
         ptr->blahblah
    }
}

MojaKlasa client
pthread_create(....., MojaKlasa::Thread, &client);

3) z uzyciem Boost::thread oraz Boost::bind mozna stworzyc watek z metody klasy, przepraszam za niedokladny przykald, ale mam niewiele czasu

class MojaKlasa
{
public:
      void Thread()
      { costam }
}

MojaKlasa client;
boost::thread watek(boost::bind(&MojaKlasa::Thread, &client));
//watek juz chodzi!
watek.join(); //czekamy az sie zakonczy
0

Innym trikiem jest użycie virtualnych metod bez parametów, wtedy masz dostęp do instancji klasy (this)

#pragma comment(linker,"/entry:main")
#include "windows.h"

class CBlah
{
    virtual __stdcall Thread1() {MessageBox(0,"thread 1","thread 1",0);}
    virtual __stdcall Thread2() {MessageBox(0,"thread 2","thread 2",0);}
};

int main()
{
    CBlah b;
    DWORD id;
    LPTHREAD_START_ROUTINE *jumptable = *(LPTHREAD_START_ROUTINE**)&b;
    CloseHandle(CreateThread(0, 0, jumptable[0], &b, 0, &id));
    CloseHandle(CreateThread(0, 0, jumptable[1], &b, 0, &id));
    return MessageBox(0,"click me","waiting",0);
}
0

Jeszcze innym trikiem jest użycie Boost::Threads

#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>

class seeker
{
    boost::mutex m;
    bool finished;

    void check()
    {
        {
            boost::mutex::scoped_lock lock(m);
            finished = false;
        }

        int m_secs(2000);
        boost::xtime xt;
        boost::xtime_get (&xt, boost::TIME_UTC);
        xt.sec += m_secs;

        for(int i=0; i < 10; ++i)
        {
            boost::thread::sleep(xt);
            xt.sec += m_secs;
        }

        {
            boost::mutex::scoped_lock lock(m);
            finished=true;
        }
    }

    void animate()
    {
        int m_secs(250);
        boost::xtime xt;
        boost::xtime_get (&xt, boost::TIME_UTC);
        xt.sec += m_secs;

        while(!finished)
        {
            for(int i=0; i < 3; ++i)
            {
                std::cout << ".";
                boost::thread::sleep(xt);
            }
            std::cout << "\r";
        }

        std::cout << "\nFinished" << std::endl;
    }

public:

    seeker(): finished(false) {}

    void seek()
    {
        boost::thread thrd1( boost::bind<void>(boost::mem_fn(&seeker::check), this) );
        thrd1.join(); 
    }
};

int main()
{
    return 0;
}

Najważniejsza jest metoda void seek().

Podsumowując:

  • można

  • przenośne

  • nowoczesne

  • bezpieczne

  • mogą być drobne błędy w tym przykładzie, bo wyciągnięty z głębokich archiwów ;p

0

dziex - powtarzasz moja odpowiedz

sapero - nie mozesz polegac na tym, ze vtable jest na samym poczatku obiektu, a juz w ogóle-w ogóle ze funkcje w vtable beda w kolejnosci takiej jak ty napisales w kodzie

0

@quetzalcoatl
Nie do końca, ja pokazałem jak zrobić to wewnątrz metody jakiejś klasy, co jest trochę trudniejsze. Poza tym nie napisałeś zbyt dużo wyjaśnień.

Aha @pawcyk dzięki boost::bind przekażesz dowolną ilośc parametrów do wątku.

0

DzieX:

do konca, zacytuje sam siebie:

3) z uzyciem Boost::thread oraz Boost::bind mozna stworzyc watek z metody klasy, przepraszam za niedokladny przykald, ale mam niewiele czasu

boost::thread watek(boost::bind(&MojaKlasa::Thread, &client));
//watek juz chodzi!
watek.join(); //czekamy az sie zakonczy

a teraz Ciebie

boost::thread thrd1( boost::bind<void>(boost::mem_fn(&seeker::check), this) );
thrd1.join();

w dodatku uzyles bind z jawna specyfikacja typu zwracanego (z czym bind by sam sobei poradzil) oraz neipotrzebnie uzyles mem_fn zeby opakowac seeker::check.. masz to samo tylko niepotrzebnie dodatkowo zagmatwane. i w dodatku tez nie napisales zadnych wyjasnien do wielkiego kawala kodu, ktorego 95% nie jest potrzebne zeby powiedziec jak uzyc boost::thread

poza tym - dzieki boost::bind nie przekazesz dowolnej ilosci parametrow. jest ograniczenie o kilkunastu. mozna je sobie powiekszyc np. do 30tu wygenerowujac automatycznie nowe pliki .h dolaczonym w booscie skryptem, ale ograniczenie jest i bedzie zawsze jakies.

poza tym - poprzez pthread tez mozna przekazac dowolna ilosc parametrow - wystarczy je opakowac w structa i przekazac wskaznik na niego, ale to oczywscie jest "na okolo".

0
dziex napisał(a)
  • mogą być drobne błędy w tym przykładzie, bo wyciągnięty z głębokich archiwów ;p

Ja też zacytuję.

quetzalcoatl napisał(a)

poza tym - dzieki boost::bind nie przekazesz dowolnej ilosci parametrow. jest ograniczenie o kilkunastu. mozna je sobie powiekszyc np. do 30tu wygenerowujac automatycznie nowe pliki .h dolaczonym w booscie skryptem, ale ograniczenie jest i bedzie zawsze jakies.

Żaden normalny programista nie wykorzysta nawet kilkunastu.

quetzalcoatl napisał(a)

poza tym - poprzez pthread tez mozna przekazac dowolna ilosc parametrow - wystarczy je opakowac w structa i przekazac wskaznik na niego, ale to oczywscie jest "na okolo".

A co jeśli masz do czynienia z funkcją biblioteczną która przyjmuje konkretne parametry a nie wskaźnik do struktury? Oczywiście można napisać sobie dodatkową funkcję która to zrobi, a którą z kolei my przekażemy do wątku. I tak dalej... Ogólnie nie lubie pisać czegoś co już dawno zostało napisane.

Aha, dochodzi jeszcze rzutowanie void*.

quetzalcoatl napisał(a)

w dodatku uzyles bind z jawna specyfikacja typu zwracanego (z czym bind by sam sobei poradzil) oraz neipotrzebnie uzyles mem_fn zeby opakowac seeker::check.. masz to samo tylko niepotrzebnie dodatkowo zagmatwane. i w dodatku tez nie napisales zadnych wyjasnien do wielkiego kawala kodu, ktorego 95% nie jest potrzebne zeby powiedziec jak uzyc boost::thread

Jawna specyfikacja zapisu to żaden błąd, wręcz poprawia czytelność kodu (o ile ktoś wie o co chodzi). mem_fn pojawiła się w tym kodzie przypadkowo - eksperymentowałem trochę.

0

quetzalcoatl, nie wprowadzaj ludzi w błąd takimi posłyszeniami.
Vtable zawsze jest jako pierwsza zmienna klasy, a kolejność adresów w niej też odpowiada kolejności w kodzie. Gdyby tak nie było to używanie np. MFC byłoby niebezpieczne, ba, windows nie miałby prawa działać bo opiera się na takich właśnie klasach.
Taki jest standard i nikt tego nie podważy.

0

sapero - to jest zdefiniwane w standardzie c++? nie pamietam.. wydawalo mi sie ze to jest platform-specific i windowsy moga sobie miec jeden uklad, linux inny, a mac z kosmosu.. w takim razie bije sie w piersi i przepraszam

dziex - alez calkowicie sie zgadzam, ogolnie to chcialem tylko powiedziec ze juz o boost::thread/boost::bind pisalem i ze sprowadza sie w zasadzie tylko do 2 prostych linijek.. wyznaje zasade ze im zwiezlejszy przyklad tym lepiej bedzie zrozumiany. a przyczepilem sie do stwierdzenia "bind - dowolna" , poniewaz <ort>w ogóle </ort>jest jakies ograniczenie w ilosci bezposrednich parametrow dla boost::bind (i dla boost::lambda::bind tez!) i przez to nie udaje czasem sie zbindowac na przyklad jakies funkcji z WINAPI - i sam wiesz ile potrafia miec parametrow i jak czytelne sa komunikaty o bledach z bind.. ja stracilem kiedys 3 godziny na szykaniu bledu, zanim przypadkiem natrafilem na #define informuajcy o wysokosci ograniczenia..

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