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);
  1. 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:

  1. 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::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..

0

@quetzalcoatl

Fakt, sory za wprowadzanie w błąd.

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