boost教程(六):多线程

每一部分都单独注释的,运行时取消注释,将其他部分注释起来就可以。

第一部分:线程管理

#include <boost/thread.hpp> 
#include <iostream> 


/*
http://zh.highscore.de/cpp/boost/multithreading.html
*/
void wait0(int seconds)
{

	//传递一个类型为 boost::posix_time::seconds 的对象,
	boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

void thread0()
{
	for (int i = 0; i < 5; ++i)
	{
		//wait() 可以调用一个名为 sleep() 的函数
		wait0(1);
		std::cout << i << std::endl;
	}
}


void thread1()
{
	try
	{
		for (int i = 0; i < 5; ++i)
		{
			//wait也是中断点
			wait0(1);
			std::cout << i << std::endl;
		}
	}
	catch (boost::thread_interrupted&)
	{
	}
}
//测试的话,将test换为 main
int test()
{
	//**********线程管理
	//一个线程总是在一开始就绑定到一个类型为 boost::thread 的变量,
	//还存在着一个叫 detach() 的方法,允许类型为 boost::thread 的变量从它对应的线程里分离。
	//boost::thread t(thread0);
	//为了防止程序终止,就需要对新建线程调用 join() 方法。 join() 方法是一个阻塞调用:
	//它可以暂停当前线程,直到调用 join() 的线程运行结束。
	//t.join();



	
	//boost::thread t(thread1);
	//wait0(3);
	在一个线程对象上调用 interrupt() 会中断相应的线程。
	它会在这个线程中抛出。 然后这只有在线程达到中断点时才会发生。
	每当一个线程中断点,它就会检查 interrupt() 是否被调用过。
	如果给定的线程不包含任何中断点,简单调用 interrupt() 就不会起作用。
	//t.interrupt();
	//t.join();



	std::cout << boost::this_thread::get_id() << std::endl;
	//静态方法它能够返回基于CPU数目或者CPU内核数目的刻在同时在物理机器上运行的线程数。
	//可以确定在一个多核程序可以同时运行的理论最大线程数。
	std::cout << boost::thread::hardware_concurrency() << std::endl;

	system("pause");
	return 0;
}

第二部分:线程同步

#include <boost/thread.hpp> 
#include <iostream> 

#include <iostream> 
#include <vector> 
#include <cstdlib> 
#include <ctime> 

void wait1(int seconds)
{
	boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}

boost::mutex mutex0;

void thread3()
{
	for (int i = 0; i < 5; ++i)
	{
		wait1(1);
		mutex0.lock();
		std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
		mutex0.unlock();
	}
}

//使用 boost::lock_guard 类也是可以的。
void thread4()
{
	for (int i = 0; i < 5; ++i)
	{
		wait1(1);
		/*
		boost::lock_guard 在其内部构造和析构函数分别自动调用 lock() 和 unlock() 。
		*/
		boost::lock_guard<boost::mutex> lock(mutex0);
		std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
	}
}

//一个重要的就是 boost::unique_lock
//虽然 boost::mutex 提供了 lock() 和 try_lock() 两个方法,但是 boost::timed_mutex 只支持 timed_lock() ,
//如果不用 timed_lock() 的话,也可以像以前的例子那样用 boost::mutex。
boost::timed_mutex mutex1;
void thread5()
{
	for (int i = 0; i < 5; ++i)
	{
		wait1(1);
		/*
		boost::unique_lock 通过多个构造函数来提供不同的方式获得互斥体。
		这个期望获得互斥体的函数简单地调用了 lock() 方法,一直等到获得这个互斥体。
		所以它的行为跟 boost::lock_guard 的那个是一样的。

		如果第二个参数传入一个 boost::try_to_lock 类型的值,对应的构造函数就会调用 try_lock() 方法。
		这个方法返回 bool 型的值:如果能够获得互斥体则返回true,否则返回 false 。 
		相比 lock() 函数,try_lock() 会立即返回,而且在获得互斥体之前不会被阻塞。
		*/
		//boost::unique_lock 这个所谓的独占锁意味着一个互斥量同时只能被一个线程获取。 其他线程必须等待,直到互斥体再次被释放。
		boost::unique_lock<boost::timed_mutex> lock(mutex1, boost::try_to_lock);

		/*
		通过 owns_lock() 可以检查是否可获得互斥体。 如果不能, owns_lock() 返回 false。
		timed_lock() 等待一定的时间以获得互斥体。
		*/
		if (!lock.owns_lock())
			lock.timed_lock(boost::get_system_time() + boost::posix_time::seconds(1));
		std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl;
		//boost::unique_lock 的析构函数也会相应地释放互斥量。
		boost::timed_mutex *m = lock.release();
		/*
		也可以像上面的例子那样,通过调用 release() 解除boost::unique_lock 和互斥量之间的关联。
		然而在这种情况下,必须显式地调用 unlock() 方法来释放互斥量,因为 boost::unique_lock 的析构函数不再做这件事情。
		*/
		m->unlock();
	}
}

boost::shared_mutex mutex2;
std::vector<int> random_numbers;

void fill0()
{
	//需要用一个 boost::unique_lock 类型的非独占锁,因为它插入了一个新的随机数到 random_numbers。
	std::srand(static_cast<unsigned int>(std::time(0)));
	for (int i = 0; i < 3; ++i)
	{
		boost::unique_lock<boost::shared_mutex> lock(mutex2);
		random_numbers.push_back(std::rand());
		//lock.unlock();
		wait1(1);
	}
}

void print0()
{
	for (int i = 0; i < 3; ++i)
	{
		wait1(1);
		boost::shared_lock<boost::shared_mutex> lock(mutex2);
		std::cout << random_numbers.back() << std::endl;
	}
}

int sum = 0;

void count0()
{
	for (int i = 0; i < 3; ++i)
	{
		wait1(1);
		boost::shared_lock<boost::shared_mutex> lock(mutex2);
		sum += random_numbers.back();
	}
}



boost::mutex mutex3;
boost::condition_variable_any cond;
std::vector<int> random_numbers1;

void fill1()
{
	std::srand(static_cast<unsigned int>(std::time(0)));
	for (int i = 0; i < 3; ++i)
	{
		boost::unique_lock<boost::mutex> lock(mutex3);
		random_numbers1.push_back(std::rand());
		/*
		为了防止其他线程同时访问这个容器,就要相应得使用一个排它锁。 不是等待一秒,实际上这个例子却用了一个条件变量。
		调用 notify_all() 会唤醒每个那些正在分别通过调用wait() 等待此通知的线程。
		*/
		cond.notify_all();
		//调用 wait() 会释放相应的被参数传入的互斥量。相应地释放线程。
		cond.wait(mutex3);
	}
}

void print1()
{
	std::size_t next_size = 1;
	for (int i = 0; i < 3; ++i)
	{
		boost::unique_lock<boost::mutex> lock(mutex3);
		//目的是为了处理在 print() 函数里第一次调用 wait() 函数之前随机数已经放到容器里。
		while (random_numbers1.size() != next_size)
			cond.wait(mutex3);
		std::cout << random_numbers1.back() << std::endl;
		++next_size;
		cond.notify_all();
	}
}


int test2()
{
	/*boost::thread t1(thread3);
	boost::thread t2(thread3);
	t1.join();
	t2.join();*/


	//使用 boost::lock_guard 类也是可以的。

	/*boost::thread t1(thread4);
	boost::thread t2(thread4);
	t1.join();
	t2.join();*/

	/*boost::thread t1(thread5);
	boost::thread t2(thread5);
	t1.join();
	t2.join();*/

	//非独占锁,(相当于读写锁,读的话可以线程同时访问,写的话同时只有一个线程)
	/*
	print() 和 count() 都可以只读访问 random_numbers 。
	由于没有函数修改 random_numbers,所有的都可以在同一时间用 boost::shared_lock 类型的非独占锁访问它。
	*/
	/*boost::thread t1(fill0);
	boost::thread t2(print0);
	boost::thread t3(count0);
	t1.join();
	t2.join();
	t3.join();
	std::cout << "Sum: " << sum << std::endl;*/

	//条件变量(生产者与消费者问题)
	boost::thread t1(fill1);
	boost::thread t2(print1);
	t1.join();
	t2.join();


	system("pause");
	return 0;
}

第三部分:本地存储

#include <boost/thread.hpp> 
#include <iostream> 
#include <cstdlib> 
#include <ctime> 

void init_number_generator0()
{
	//产生器只要初始化一次, init_number_generator() 用了一个静态变量 done 作为条件量。
	static bool done = false;
	if (!done)
	{
		done = true;
		//随机数产生器,通过 std::time() 返回当前时间, 在 init_number_generator() 函数里完成初始化。 
		std::srand(static_cast<unsigned int>(std::time(0)));
	}
}

boost::mutex mutex4;

void random_number_generator0()
{
	init_number_generator0();
	int i = std::rand();
	boost::lock_guard<boost::mutex> lock(mutex4);
	std::cout << i << std::endl;
}


//这个程序有个缺陷:std::rand() 所用的产生器必须被各个线程初始化。 因此 init_number_generator() 
//的实现实际上是不对的,因为它只调用了一次 std::srand() 。使用TLS,这一缺陷可以得到纠正。
//三个线程在同一时间被创建,从而造成随机数生成器在同一时间初始化。
//如果该程序执行了几次,随机数就会改变,这就表明生成器初始化正确了。
void init_number_generator1()
{
	/*
	tls 工作起来就像 done :它可以作为一个条件指明随机数发生器是否被初始化。 
	但是关键的区别,就是 tls 存储的值只对相应的线程可见和可用。
	它期望得到一个 bool 型变量的地址,而非它本身。
	使用 reset() 方法,可以把它的地址保存到 tls 里面。
	*/
	static boost::thread_specific_ptr<bool> tls;
	if (!tls.get())
		tls.reset(new bool(false));
	if (!*tls)
	{
		*tls = true;
		std::srand(static_cast<unsigned int>(std::time(0)));
	}
}

boost::mutex mutex5;

void random_number_generator1()
{
	init_number_generator1();
	int i = std::rand();
	boost::lock_guard<boost::mutex> lock(mutex5);
	std::cout << i << std::endl;
}


int main()
{

	//线程私有数据
	//线程本地存储(TLS)的变量可以被看作是一个只对某个特定线程而非整个程序可见的全局变量。
	boost::thread t[3];
	//这个程序有个缺陷:std::rand() 所用的产生器必须被各个线程初始化。 因此 init_number_generator() 
	//的实现实际上是不对的,因为它只调用了一次 std::srand() 。使用TLS,这一缺陷可以得到纠正。
	/*for (int i = 0; i < 3; ++i)
		t[i] = boost::thread(random_number_generator0);

	for (int i = 0; i < 3; ++i)
		t[i].join();*/

	for (int i = 0; i < 3; ++i)
		t[i] = boost::thread(random_number_generator1);

	for (int i = 0; i < 3; ++i)
		t[i].join();


	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值