Reputation: 443
There is a code sample:
class MY_Timer
{
// ...
void start(const UInt timeOut, const UInt events, CALLBACK_TARGET reciever)
{
cout << __FUNCTION__ << " " << timerName << endl;
if (active) return;
if ((0u == timeOut) || (0u == events)) return;
if (nullptr == reciever) return;
interval = timeOut;
eventsAmount = events;
active = true;
cb_target = reciever;
thread clockieThread(&MY_Timer::clockie, this); // комментарий
clockieThread.join();
};
private:
void clockie()
{
while (eventsAmount--)
{
Sleep(interval);
cb_target(timerName, eventsAmount);
}
active = false;
}
// ...
};
void target(const char * timerName, const UInt data)
{
cout << timerName << " DATA: " << data << endl;
}
int main()
{
MY_Timer * tOne = new MY_Timer("ALPHA");
MY_Timer * tTwo = new MY_Timer("OMEGA");
tOne->start(200, 10, &target);
tTwo->start(300, 20, &target);
}
This is what output is looks like:
MY_Timer::start ALPHA
ALPHA DATA: 9
ALPHA DATA: 8
ALPHA DATA: 7
ALPHA DATA: 6
ALPHA DATA: 5
ALPHA DATA: 4
ALPHA DATA: 3
ALPHA DATA: 2
ALPHA DATA: 1
ALPHA DATA: 0
MY_Timer::start OMEGA
OMEGA DATA: 9
OMEGA DATA: 8
OMEGA DATA: 7
OMEGA DATA: 6
OMEGA DATA: 5
OMEGA DATA: 4
OMEGA DATA: 3
OMEGA DATA: 2
OMEGA DATA: 1
OMEGA DATA: 0
Could you please explain why this code behaviour is like there is only one execution flow. I thought output will be mixed with messages from two threads, like if I will do this:
void foo(const char * name, int interval)
{
int step = 10;
while (step--)
{
Sleep(interval);
cout << name << " step: " << step << endl;
}
}
int main()
{
thread t1(foo, "ALPHA", 200);
thread t2(foo, "OMEGA", 300);
t1.join();
t2.join();
return 0;
}
And output will be like: "OMG, MULTITHREADING!":
ALPHA step: 9
OMEGA step: 9
ALPHA step: 8
OMEGA step: 8
ALPHA step: 7
ALPHA step: 6
OMEGA step: 7
ALPHA step: 5
OMEGA step: 6
ALPHA step: 4
ALPHA step: 3
OMEGA step: 5
ALPHA step: 2
OMEGA step: 4
ALPHA step: 1
ALPHA step: 0
OMEGA step: 3
OMEGA step: 2
OMEGA step: 1
OMEGA step: 0
Thank you!
Upvotes: 1
Views: 85
Reputation: 1412
This is the culprit:
thread clockieThread(&MY_Timer::clockie, this); // комментарий
clockieThread.join();
If you think about what this does, and expand your code, the result would look a bit like this:
int main()
{
MY_Timer * tOne = new MY_Timer("ALPHA");
MY_Timer * tTwo = new MY_Timer("OMEGA");
tOne->start(200, 10, &target);
// clockieThread1 created
// clockieThread1 joined (blocks until complete)
tTwo->start(300, 20, &target);
// clockieThread2 created
// clockieThread2 joined (blocks until complete)
return 0;
}
You are joining the thread immediately after creating it, and so it blocks everything until the thread finishes.
What you probably want is to have the thread be a member of the class, and you can start/join it.
class MY_Timer
{
thread clockieThread;
...
void start(const UInt timeOut, const UInt events, CALLBACK_TARGET reciever)
...
clockieThread = thread(&MY_Timer::clockie, this);
// Remove the clockieThread.join() here
}
void join() {
clockieThread.join();
}
}
Then with that change, you can do the following:
int main()
{
MY_Timer * tOne = new MY_Timer("ALPHA");
MY_Timer * tTwo = new MY_Timer("OMEGA");
tOne->start(200, 10, &target);
tTwo->start(300, 20, &target);
tOne->join();
tTwo->join();
return 0;
}
If you want to eliminate the tOne->join()
calls entirely though, you could do the join inside the destructor for the class:
class MY_Timer
{
...
~MY_Timer() {
clockieThread.join();
}
}
Upvotes: 2
Reputation: 1153
As the commentator said, "join()" blocks the main thread until your newly spawned thread has finished completing, so when you call your "start" function - it creates the thread then waits for it to finish.
thread clockieThread(&MY_Timer::clockie, this); // комментарий
clockieThread.join();
You can use "std::thread::detach" to let the thread finish on its own - but you won't be able to keep track of threads you do this to.
Upvotes: 0