I made synchronization of the operation of two threads created by the Example class by some super crutch method (using the test from the ID), how can I properly implement completion of 1 stream after starting 2?
That is, I create an example class an object in Main’e – & gt; The constructor starts 1 stream, which with an interval of 2 seconds displays a message with a stream ID into the console. Main stream sleep for 10 seconds, after which I launch 2 stream. Because 2 Stream is launched, I need 1 stream, waking up, immediately completed my work without performing any actions inside the cycle. Probably, theoretically correct will do it with Mutex, but I have not yet understood how.
result, if you do not add a test with ID (2 streams operate at once):
16596
16596.
16596.
16596.
16596.
9104.
16596.
9104.
16596.
9104.
16596.
9104.
16596.
9104.
16596.
9104.
Result (the one that I just needed created 2 stream no longer works in parallel with 1, because The first completed its work, stopping the cycle) with check ID:
18356
18356.
18356.
18356.
18356.
15788.
15788.
15788.
15788.
15788.
# include & lt; iostream & gt;
#Include & lt; Thread & GT;
#Include & lt; mutex & gt;
#Include & lt; atomic & gt;
#Include & lt; Chrono & gt;
Class example.
{
STD :: Atomic_Bool M_DO_LOOP_ITERATION;
STD :: Thread M_Thread;
std :: mutex m_mutex;
STD :: Atomic_int M_ID;
Void Start ()
{
M_ID ++;
m_thread = std :: thread ([& amp] ()
{
// STD :: LOCK_GUARD & LT; STD :: MUTEX & GT; lock (m_mutex);
int ID = M_ID.LOAD ();
While (do_loop_iteration ())
{
If (id! = M_ID.Load ())
{
Break;
}
STD :: COUT & LT; & LT; std :: this_thread :: get_id () & lt; & lt; STD :: ENDL;
Std :: This_Thread :: Sleep_for (STD :: Chrono :: Seconds (2));
}
});
}
Public:
Example ():
M_DO_LOOP_ITERATION (TRUE),
M_ID (0)
{
start ();
}
BOOL DO_LOOP_ITERATION ()
{
RETURN M_DO_LOOP_ITERATION.LOAD ();
}
Void Restart ()
{
m_thread.detach ();
start ();
}
};
INT MAIN ()
{
EXAMPLE EX;
Std :: This_Thread :: Sleep_for (STD :: Chrono :: Seconds (10));
EX.Restart ();
Std :: This_Thread :: Sleep_for (STD :: Chrono :: Seconds (9999999));
Return 0;
}
Answer 1, Authority 100%
Mutex alone allows you to block the simultaneous access of several streams to the code section. But Condition_Variable is more suitable for such a case, since it allows you to expect anything no burning crutches from Sleep or Busy Loop.
# include & lt; iostream & gt;
#Include & lt; Thread & GT;
#Include & lt; mutex & gt;
#Include & lt; atomic & gt;
#Include & lt; Chrono & gt;
#include & lt; Condition_Variable & GT;
Class example.
{
:: STD :: Thread M_Thread;
:: std :: mutex m_mutex;
:: STD :: CONDITION_VARIABLE M_COND;
BOOL M_LOOP;
int m_counter;
Private: Void Start (Void)
{
M_Loop = True;
m_thread = :: std :: thread {& amp; example :: thread_routine, this};
}
Private: Void Thread_Routine (Void)
{
:: STD :: UNIQUE_LOCK LOCK {M_MUTEX};
do.
{
:: STD :: COUT & LT; & LT; M_COUNTER & LT; & LT; :: STD :: ENDL;
}
While
(
not m_cond.wait_for
(
lock
, :: Std :: Chrono :: Seconds {1}
, [this] (void)
{
Return NOT M_LOOP;
}
)
);
}
Private: Void Stop (Void)
{
{
:: STD :: LOCK_GUARD LOCK {M_MUTEX};
M_loop = false;
}
M_COND.Notify_one ();
m_thread.join ();
++ m_counter;
}
public: example (void): m_loop {}, m_counter {}
{
start ();
}
public: ~ example (void)
{
stop ();
}
public: void restart (void)
{
stop ();
start ();
}
};
int main ()
{
example ex {};
for (;;)
{
:: std :: this_thread :: sleep_for (:: std :: chrono :: seconds {3});
ex.restart ();
}
return 0;
}
Answer 2
# include & lt; iostream & gt;
#include & lt; thread & gt;
#include & lt; mutex & gt;
#include & lt; atomic & gt;
#include & lt; chrono & gt;
#include & lt; condition_variable & gt;
class Gateway
{
std :: thread m_thread;
std :: condition_variable m_cond_var;
std :: mutex m_mutex;
std :: atomic_bool m_connected;
void connect ();
public:
void on_close (bool reconnect = false);
bool is_connected () const;
Gateway ();
~ Gateway ();
};
void Gateway :: connect ()
{
std :: cout & lt; & lt; "Gateway :: connect - start" & lt; & lt; std :: endl;
m_connected = true;
m_thread = std :: thread ([& amp;] ()
{
std :: unique_lock & lt; std :: mutex & gt; lock (m_mutex);
while (is_connected ())
{
std :: cout & lt; & lt; "ping" & lt; & lt; std :: this_thread :: get_id () & lt; & lt; std :: endl;
m_cond_var.wait_for (lock, std :: chrono :: seconds (2), [& amp;] () {return not is_connected ();});
}
});
std :: cout & lt; & lt; "Gateway :: connect - end" & lt; & lt; std :: endl;
}
void Gateway :: on_close (bool reconnect)
{
std :: cout & lt; & lt; "Gateway :: on_close - start" & lt; & lt; std :: endl;
if (is_connected ())
{
m_connected = false;
m_cond_var.notify_one ();
m_thread.join ();
}
if (reconnect)
connect ();
std :: cout & lt; & lt; "Gateway :: on_close - end" & lt; & lt; std :: endl;
}
bool Gateway :: is_connected () const
{
return m_connected.load ();
}
Gateway :: Gateway ():
m_connected (false)
{
connect ();
}
Gateway :: ~ Gateway ()
{
m_connected = false;
m_cond_var.notify_one ();
if (m_thread.joinable ())
m_thread.join ();
}
int main ()
{
std :: cout & lt; & lt; "main - start" & lt; & lt; std :: endl;
{
Gateway gateway;
std :: this_thread :: sleep_for (std :: chrono :: seconds (10));
gateway.on_close (true);
std :: this_thread :: sleep_for (std :: chrono :: seconds (20));
}
std :: cout & lt; & lt; "main - end" & lt; & lt; std :: endl;
return 0;
}