essay on programming languages, computer science, information techonlogies and all.

Wednesday, June 13, 2018

C++ thread

std::thread with static function


#include 

void called_from_static_fn( const std::string& arg )
{
  // ...
}

std::thread t1(called_from_static_fn, "static");
// ...
t1.join();

std::thread with member fn


class Foo
{
public:
	void Bar( const string& arg)
	{
		// ...
	}
};

Foo foo;
thread t1(&Foo::Bar, &foo, "member");
// ...
t1.join();

std::thread with lambda


int ret = 0;
thread t( [ &ret ](int m, int n) { ret = m + n; }, 2, 4 );
t.join();

std::thread in array


static int twice(int m) { return 2 * m; }

vector< thread > threads;
for (int i = 0; i < 10; ++i)
{
  threads.push_back( thread(twice, i));
}

for (auto& t : threads)
{
  t.join();
}

catch exception in a thread


static int DoNotTryAtHome()
{
  throw exception("I said NO");
}

thread t1(DoNotTryAtHomeNoThrow);
t1.join();

use mutex on shared variable


class Foo 
{
	int m_Bar = 0;
	mutex m_LockBar;
public:
	void AddBarSafe(int add)
	{
		lock_guard< mutex > guard(m_LockBar);
		int temp = m_Bar;
		this_thread::sleep_for(chrono::milliseconds(10));
		m_Bar = temp + add;
	}
};

{
	Foo foo;
	vector ts;
	ts.emplace_back(thread{ &Foo::AddBarSafe, &foo, 2 });
	ts.emplace_back(thread{ &Foo::AddBarSafe, &foo, 3 });
	ts.emplace_back(thread{ &Foo::AddBarSafe, &foo, 4 });

	for (auto& t : ts) {  t.join(); }
}

std::thread on class operator()


struct funcCount
{
	int &i;
	funcCount(int& i_) : i(i_) {}
	void operator()()
	{
		for (unsigned j = 0; j < 1000; ++j)
		{
			++i;
			this_thread::sleep_for(chrono::milliseconds(1));
		}
	}
};

{
	int some_local_state = 0;
	funcCount my_func(some_local_state);
	std::thread my_thread(my_func);
	// my_thread.detach();				// undefined behaviour
	my_thread.join();
}

thread_guard


class thread_guard
{
	std::thread& t;
public:
	explicit thread_guard(std::thread& t_) : t(t_) {}
	~thread_guard() 
	{ 
		if (t.joinable()) t.join(); 
	}

	thread_guard(thread_guard const&) = delete;
	thread_guard operator = (thread_guard const &) = delete;
};

void do_something_stupid()
{
	for (int i = 1; i < 10; ++i)
	{
		if (i % 5 == 0)
		{
			throw std::exception("ooops");
		}
	}
}

{
	int some_local_state = 0;
	try
	{
		funcCount my_func(some_local_state);
		std::thread t(my_func);
		thread_guard g(t);
		do_something_stupid();
	}
	catch (...)
	{
	}
}

move around thread


{
	std::thread t1(called_from_static_fn, "static");
	std::thread t2 = std::move(t1);
	t1 = std::thread(&TestMultiThread::called_from_member_fn, this, "static");
	std::thread t3;
	t3 = std::move(t2);
	// t1 = std::move(t3);   //  terminate

	t1.join();
	t3.join();
}

async


{
	future result(async(called_from_static_fn, "static"));
	result.get();
}

{
	Foo foo;
	future result(async(&Foo::Bar, &foo, "member"));
	result.get();
}

{
	future result(async([](int m, int n) { return m + n; }, 2, 4));
	int ret = result.get();
}

{
	vector< future< int > > futures;
	for (int i = 0; i < 10; ++i)
	{
		futures.push_back(async(twice, i));
	}

	for (auto& e : futures)
	{
		cout << e.get() << endl;
	}
}

async will throw exception at convenient time


{
	future result(async(DoNotTryAtHome));
		
	try
	{
		int ret = result.get();
	}
	catch (exception& ex)
	{
		printf("exception caught : %s", ex.what());
	}
}

wait for future


{
	future f = async( [](){ cout << "bar" << endl; } );
		
	if (f.wait_for(chrono::milliseconds(0)) == future_status::deferred)
	{
		cout << "foo and wait for bar" << endl;
		f.get();
	}
	else
	{
		while (f.wait_for(chrono::milliseconds(10)) != future_status::ready)
		{
			cout << "foo waiting ... " << endl;
		}

		cout << "foo" << endl;
	}
}

condition_variable


{
	mutex m_LockReadyProcess;
	condition_variable m_Condition;
	string m_Log;
	bool m_Ready = false;
	bool m_Processed = false;
}

void worker_thread()
{
	unique_lock lock(m_LockReadyProcess);
	m_Condition.wait(lock, [=]{return m_Ready; });

	cout << "Worker thread is processing data\n";
	m_Log += " after processing";

	m_Processed = true;
	cout << "Worker thread signals data processing completed\n";

	lock.unlock();
	m_Condition.notify_one();
}

{
	thread worker( &TestMultiThread::worker_thread, this);

	m_Log = "Example data";

	{
		lock_guard guard(m_LockReadyProcess);
		m_Ready = true;
		cout << "main() signals data ready for processing\n";
	}
	m_Condition.notify_one();

	{
		unique_lock lock(m_LockReadyProcess);
		m_Condition.wait(lock, [=]{return m_Processed; });
	}
	cout << "Back in main(), data = " << m_Log << '\n';

	worker.join();
}

No comments: