C++11 多线程2——Mutex的错误使用

本系列文章主要介绍C++11中多线程的使用方法,主要参考书籍为《C++Concurrency IN Action》。

 

为了保证多线程访问数据的安全性,一种通常的做法是对需要保护的数据上锁,使用mutex保证互斥访问。可以使用的做法是调用lock()unlock()函数,但是我们更加推荐使用模板类std::lock_guard,在该类的构造函数中完成lock(),而在析构函数中完成unlock()操作。这一技巧和上一章对join()函数的使用是一致的。

 

简单介绍后我们来看一个可能引起mutex使用错误的例子。


#include <iostream>
#include <thread>
#include <mutex>
class some_data
{
public:	
	int a;
	std::string b;

	void do_someting(){ 
		a--;
		std::cout << "Break the protected." << endl; 
		std::cout << "a:" << a << endl;
	};
};
class data_wrapper
{
private:
	some_data data;
	std::mutex m;
public:
	template<typename Function>
	void process_data(Function func)
	{
		std::lock_guard<std::mutex> l(m);

		func(data);		// 1、将受保护的数据传递给func函数 [8/28/2015 pan]
	}
	void printData(){
		cout << "cuttent data:" << data.a << endl;
	}
};



some_data* unprotected=NULL;
void malicious_function(some_data& protected_data)
{
	unprotected = &protected_data;
	for (int i = 0; i < 100; i++){
		unprotected->a++;
		cout << "a should in protected:" << unprotected->a << endl;
	}
}

data_wrapper x;

void wrap()
{
	while (true)
	{
		if (unprotected != NULL){
			unprotected->do_someting();<span style="white-space:pre">	</span>// 4、“未经授权”的访问保护对象
		}
	}
}

void main()
{
	thread t(wrap);<span style="white-space:pre">			</span>// 2、开启一个新线程测试
	
	x.process_data(malicious_function);		// 3、传递一个恶意函数 [8/28/2015 pan]
	t.join();
	x.printData();
}


程序分析:

在main()函数中我们首先开启了一个新的线程去执行wrap()函数,函数在uprotected指针不为空时尝试去访问受保护的对象。

x.process_data()函数对保护数据上锁,但是把data对象的引用传递给了不受控制的恶意函数malicious_function()。如果互斥对象mutex能正常发挥作用,线程t对数据的访问会被挂起,我们应该能顺利执行完100次遍历之后再将控制权传递给线程t。线程t中函数do_someting()用来测试数据的保护性是否被破坏。


实际执行情况是do_someting()与malicious_function()中for循环交替执行,表明数据为能受到保护。






  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C++ 中,我们可以使用线程库来实现多线程编程。线程的挂起、唤醒与终止是多线程编程中非常重要的一部分。 线程的挂起也称为线程的休眠,它可以让线程停止运行一段时间,等待某个条件满足后再继续运行。在 C++ 中,我们可以使用 std::this_thread::sleep_for() 函数来实现线程的挂起,该函数可以让当前线程挂起一段时间,例如: ```cpp #include <chrono> #include <thread> int main() { // 挂起当前线程 1 秒钟 std::this_thread::sleep_for(std::chrono::seconds(1)); return 0; } ``` 线程的唤醒可以通过条件变量来实现,条件变量是一种同步机制,用于在线程之间传递信号。在 C++ 中,我们可以使用 std::condition_variable 类来创建条件变量,然后使用 wait() 函数来挂起线程等待条件变量的信号,使用 notify_one() 函数来唤醒一个等待条件变量的线程,例如: ```cpp #include <condition_variable> #include <mutex> #include <thread> std::condition_variable cv; std::mutex mtx; bool ready = false; void worker_thread() { // 等待条件变量的信号 std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, [](){ return ready; }); // 条件满足后继续执行 // ... } int main() { // 唤醒等待条件变量的线程 { std::lock_guard<std::mutex> lock(mtx); ready = true; } cv.notify_one(); return 0; } ``` 线程的终止可以使用 std::thread::join() 函数来实现,该函数可以让当前线程等待另一个线程执行完成后再继续执行,例如: ```cpp #include <thread> void worker_thread() { // ... } int main() { std::thread t(worker_thread); // 等待 worker_thread 执行完成 t.join(); return 0; } ``` 另外,线程的终止还可以使用 std::thread::detach() 函数来实现,该函数可以让当前线程与创建的线程分离,使得两个线程可以独立运行,例如: ```cpp #include <thread> void worker_thread() { // ... } int main() { std::thread t(worker_thread); // 分离线程,使得两个线程可以独立运行 t.detach(); return 0; } ``` 需要注意的是,分离线程后,主线程不能再使用 join() 函数等待子线程执行完成,否则会导致程序崩溃。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值