您的位置:首页 > 编程语言 > C语言/C++

第三章 数据竞争与互斥对象

2016-08-17 09:08 381 查看
案例:

#include<iostream>

#include<string>

#include<thread>

  

using namespace std;

  

void function_1()

{

for (int i = 0; i > -100; i--)
{
std::cout << "From t1:" << i << std::endl;
  

}
}

int main()

{

thread t1(function_1);
for (int i = 0; i < 100; i++)
{
cout << "From main:" << i << endl;
}
t1.join();
}

输出



  

可以看到其中有Fromt1:From main:50

原因在于代码中的cout为两个线程共同竞争使用。解决的方法使用互斥对象来同步资源访问。

#include<iostream>

#include<string>

#include<thread>

#include<mutex>

  

using namespace std;

  

std::mutex mu;

  

void shared_Print(string msg,int id)

{

  

mu.lock();
std::cout << msg << id << endl;
mu.unlock();
  
}

void function_1()

{

for (int i = 0; i > -100; i--)
{
//std::cout << "From t1:" << i << std::endl;
//using shared_Print function instead of function_1
shared_Print("From t1", i);
  

}
}

int main()

{

thread t1(function_1);
for (int i = 0; i < 100; i++)
{
//cout << "From main:" << i << endl;
shared_Print("From Main()", i);
}
t1.join();
}

  



  

但是,这样使用下,有一种情况发生时将会造成死锁的发生。

在程序mu.lock与mu.unlock之间的函数如果抛出意外,此事程序将不能解锁,从而使得程序锁住。

  

使用另外一种方式来替代:

Std::lock_guard<std::mutex>guard(mu)

  

#include<iostream>

#include<string>

#include<thread>

#include<mutex>

  

using namespace std;

  

std::mutex mu;

  

void shared_Print(string msg,int id)

{

  

std::lock_guard<std::mutex> guard(mu);
std::cout << msg << id << endl;
  

  
}

void function_1()

{

for (int i = 0; i > -100; i--)
{
//std::cout << "From t1:" << i << std::endl;
//using shared_Print function instead of function_1
shared_Print("From t1", i);
  

}
}

int main()

{

thread t1(function_1);
for (int i = 0; i < 100; i++)
{
//cout << "From main:" << i << endl;
shared_Print("From Main()", i);
}
t1.join();
}

#end

另外一个问题来了,cout是全局型的,因此其他程序段可以继续使用cout,从而没有实现完全意义上的线程保护,。即没有在互斥量mu中作为私有函数供(绑定)使用。

使用类可以解决该问题。

#include<iostream>

#include<string>

#include<thread>

#include<mutex>

#include<fstream> //将数据保存到文件中使用fsteam头文件

  

using namespace std;

  

std::mutex mu;

class lofFile

{

public:

lofFile() //
{
f.open("log.txt");
}
void share_Print(std::string id, int value) //成员函数
{
std::lock_guard<mutex> locker(m_mutex);
f << "from " << id << value << endl;
}
protected:

private:

mutex m_mutex;
ofstream f;
};

  

void function_1(lofFile& l) //添加引用

{

for (int i = 0; i > -100; i--)
{
//std::cout << "From t1:" << i << std::endl;
//using shared_Print function instead of function_1
l.share_Print("From t1", i);
  

}
}

int main()

{

lofFile l;
thread t1(function_1, std::ref(l)); //一定注意添加引用
for (int i = 0; i < 100; i++)
{
//cout << "From main:" << i << endl;
l.share_Print("From Main()", i);
}
t1.join();
}

找到文件夹下的文件



清单3.2 无意中传递了保护数据的引用

class some_data

{

int a;

std::string b;

public:

void do_something();

};

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 传递"保护"数据给用户函数

}

};

some_data* unprotected;

void malicious_function(some_data& protected_data)

{

unprotected=&protected_data;

}

data_wrapper x;

void foo()

{

x.process_data(malicious_function); // 2
传递一个恶意函数

unprotected->do_something(); // 3 在无保护的情况下访问保护数据

}

  

例子中process_data看起来没有任何问题,
std::lock_guard 对数据做了很好的保护,但调用用户提供的函数func①,就意味着foo能够绕过保护机制将函数
malicious_function 传递进去②,在没有锁定互斥量的情况下调用do_something()

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息