#include <thread>
#include <iostream>

struct Struct1
{
	void operator()()	
	{
		std::cout << "a short thread.." << std::endl;
	}
};

void func1()
{
	for (int i= 0 ; i < 1000 ; i++ )
	{
		std::cout << ".";
	}
	std::cout << std::endl;
}

int main()
{
	std::thread t(func1);
	t.join();

	Struct1 s1;
	std::thread t2(s1);
	t2.join();
    return 0;
}

class Param
{
public:
	std::string name;
	int age;
};

void func3(Param param)
{
	std::cout << "Name:" << param.name << ", Age:" << param.age << std::endl;
}

int main()
{
	Param param;
	param.name = "Lisa";
	param.age = 12;
	std::thread t3(func3, param);
	t3.join();
}

{
public:
	Struct2(Param param, double * result)
	{
		_param = param;
		_res = result;
	}

public:
	void operator()()
	{
		std::cout << "Name:" << _param.name 
<< ", Age:" << _param.age << std::endl;
		*_res = 10;
	}

private:
	double * _res;
	Param _param;
};

int main()
{
	Param param;
	param.name = "Lisa";
	param.age = 12;

	double d = 0;
	Struct2 s2(param, &d);
	std::thread t4(s2);
	t4.join();
	std::cout << "ret d=" << d << std::endl;
}

std::string _name;
std::mutex _mutex;

void func5(Param param)
{
	for (int i = 0; i < 100; i++)
	{
		std::cout << "Name:" << param.name << ", Age:" 
<< param.age << std::endl;
		_mutex.lock();
		_name = param.name;
		_mutex.unlock();
	}
}

int main()
{
	Param param;
	param.name = "Lisa";
	param.age = 12;

	Param param2;
	param2.name = "Audrey";
	param2.age = 8;

	std::thread t5(func5, param);
	std::thread t6(func5, param2);
	t5.join();
	t6.join();
}

std::shared_mutex _smutex;

void func6(Param param)
{
	for (int i = 0; i < 10000; i++)
	{
		_smutex.lock();
		_name = param.name;
		_smutex.unlock();

		_smutex.lock_shared();
		std::cout << "Name:" << _name << std::endl;
		_smutex.unlock_shared();
	}
}

int main()
{
	Param param;
	param.name = "Lisa";
	param.age = 12;

	Param param2;
	param2.name = "Audrey";
	param2.age = 8;

	std::thread t5(func6, param);
	std::thread t6(func6, param2);
	t5.join();
	t6.join();

int MySum(int i, int j)
{
	return i + j;
}

void ft()
{
	std::packaged_task<int(int, int)> task(MySum); // wrap the function
	std::future<int> f1 = task.get_future();  // get a future
	std::thread t(std::move(task), 10, 20); // launch on a thread
	f1.wait();
	std::cout << "Done! result: " << f1.get() << std::endl;
	t.join();
}

void ft3()
{
	// future from a promise
	std::promise<int> p;
	std::future<int> f3 = p.get_future();
	std::thread([&p] { p.set_value_at_thread_exit(9); }).detach();

	std::cout << "Waiting..." << std::flush;
	f3.wait();
	std::cout << "Done! result: " << f3.get() << std::endl;
}

void ft2()
{
	// future from an async()
	std::future<int> f2 = std::async(std::launch::async, [] { return 8; });
	f2.wait();
	std::cout << "Done! result: " << f2.get() << std::endl;
}