od poczatku.. ktos zamiescil pytanie w dziale newbie http://4programmers.net/Forum/viewtopic.php?id=120986 i postanowilem to sprawdzic.. skrobnalem na szybko program odpalajacy N watkow, czekajacy pomiedzy kolejnymi odpaleniami pewien kawalek czasu. kazdy pojedynczy watek mial za zadanie wylosowac i wypisac M liczb
kod wyglada jak wyglada, bo mam drobne zboczenie o nazwie 'boost' i lubie sie bawic.. :)
#include <ctime>
#include <iostream>
#include <boost/thread.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>
#include <boost/thread/mutex.hpp>
struct guarded_ostream //JEDEN
{
boost::mutex guard;
std::ostream& ostr;
guarded_ostream(std::ostream& ostream):ostr(ostream){}
};
struct letter
{
char const chr;
guarded_ostream& out;
letter(char const c, guarded_ostream& output):chr(c),out(output){}
void print_thread()
{ using namespace std;
using namespace boost;
srand((int)std::time(0)); //ZERO
unsigned long x = 3;
do
{
xtime t;
xtime_get(&t, TIME_UTC);
t.sec += 1; //TRZY
thread::sleep(t); //TRZY
mutex::scoped_lock lock(out.guard); //JEDEN, PIEC
out.ostr << chr << ':' << rand() << endl;
}while(--x);
{ mutex::scoped_lock lock(out.guard); //JEDEN, PIEC
out.ostr << chr << ':' << "!" << endl; //CZTERY
}
delete this;
}
};
int main()
{
using namespace std;
using namespace boost;
using namespace boost::lambda;
//srand((int)std::time(0)); //ZERO
string const s = "12345";
thread_group threads;
letter* tmp;
guarded_ostream go(cout);
boost::xtime t;
for_each(s.begin(), s.end(),
( var(tmp) = bind(new_ptr<letter>(), _1, var(go)),
bind(&thread_group::add_thread, var(threads),
bind(new_ptr<thread>(),
unlambda(bind(&letter::print_thread, var(tmp)))
) ),
bind(&xtime_get, &t, TIME_UTC),
var(t.nsec)+=100 * 1000 * 1000, //100 milisekund //DWA
bind(&thread::sleep, var(t))
) );
threads.join_all();
cin.get();
}
przykladowy wynik:
1:17565 //<----
2:17565 //<----
3:17568 //<---- !!
4:17568 //<----
5:17568
1:18028
2:18028
3:28776
4:28776
5:28776
1:25209
1:!
2:25209
2:!
3:10306
3:!
4:10306
4:!
5:10306
5:!
pewne rzeczy tutaj sa dziwne i nadmiarowe.. juz wyjasniam
srand'a mozna postawic w dwoch miejscach, oznaczonych ZERO. sporo ludzi odruchowo stawia je sie na starcie programu, co jak odpisalem autorowi tamtego postu - jest bledem, bo kazdy watek ma swoj seed RNG i na starcie go dziedziczy z watku glownego.. jesli postawic srand na starcie glownego watku - kazdy RNG bedzie idealnie zsynchronizowany z reszta. tak wiec srand musi byc odpalony na starcie kazdego watku z osobna. ten program to pokazuje
po napisaniu programu zauwazylem ze napisy generowane przez watki sa "posiekane".. no tak, przeciez COUT nie jest synchronizowany.. tak wiec powstalo JEDEN -- tylko po to zeby przekazac ten sam mutex do kazdego watku
sleepy w miejscach oznaczonych DWA i TRZY sa bardzo wazne - DWA rozsuwa odpalenie watkow w czasie, TRZY - gwarantuje, ze watki sie beda przecinac (tzn. nie bedzie przypadkowej serializacji, ze kazdy watek zdazy sie zakonczyc przed startem nastepnego). u mnie, jesli DWA jest ustawione na 100milisekund (tak jak jest) to co ktores odpalenie programu pokaze ze generatory sie 'rozjada'. oznaczylem to miejsce na przykladowym wyniku. czasem - owe 100ms nie wystarczy aby sie rozjechaly - to normalne !!!
ok.. mam nadzieje ze juz wszystko wiadomo, new_ptr i delete this chyba mi nikt nie zarzuci :) mam jedno spostrzezenie-ciekawostke i jedno pytanie:
ciekawostka: ten program ladnie pokazuje, ze pierwsza liczba uzyskana po srand nie jest losowa, tylko jest wprost zalezna od czasu. widac to nawet po zalaczonym wyniku programu :) jesli ustawic DWA np. na sekunde, to kazdy kolejny RNG bedzie mial pierwsza liczbe bardzo podobna, ale o pare oczek wyzsza. potem (na szczescie) juz sie rozjezdzaja
pytanie: gdzies w tym programie mam ... blad. pierwotnie sie walnalem i w miejscu DWA mialem napisane 100 * 000 * 1000, czyli zero :) a w miejscu TRZY mialem nsec zamiast sec.. efekt jest oczywisty - wszystko pedzilo bez zadnego oczekiwania. i w takim ukladzie, raz na jakis czas program wyklada sie w miejscu CZTERY, konkretniej mowiac - referencja OUT pokazuje na smieci (tzn. &out == 0xfeeefeee), tak jakby obiekt *this zostal zwolniony -- co jest nie mozliwe.. siedze nad tym od godziny i nie widze gdzie mam blad. wszystko jest zsynchronizowane.. no i nie ma szansy aby delete this wykonal sie wczesniej.. po zwiekszeniu ilosci watkow do 10 program zaczal sie wywalac takze w miejscach PIEC, z tego samego powodu. co to moze byc? sprawdzalem - threadgroup.joinall() dziala prawidlowo, nie puszcza za wczesnie..