EA&UML日拱一卒-多任务编程超入门-(7)关于mutex,你必须知道的

前一篇文章讲了一个故事,本文换一种方式继续说明。如果将两篇文章结合起来看,相信会更有趣。


这部分内容看起来简单,但却是经常出错的地方。


面临的问题


多线程同时操作一段数据时,线程调度由操作系统控制,在机器码层次进行,所以访问同一数据的多个任务(线程)的代码随机交替执行,从而导致任务(线程)间数据交换不能正常进行。


解决问题的方式


问题搞清楚以后,对策当然就是保证每个线程内操作数据的处理的完整性。但是C/C++中达成这个目标的手段不是将数据保护起来,而是限制操作数据的代码的同时执行具体说,就是在开始执行操作数据的代码之前先通过mutex::lock方法锁定互斥量,然后执行对数据进行操作的代码。数据操作代码执行完了之后,再通过mutex::unlock释放互斥量。在互斥量的锁定期间其他线程无法锁定信号量。


由于操作系统可以保证同一时刻只有一个线程可以锁定成功,所以只要程序在所有操作同一数据的代码之前都有锁定互斥量的动作,结果上就可以保证同一时刻只有一段操作数据的代码可以执行,而不被其他操作改数据的代码打断。这样就间接保证了数据的完整性。


注意事项


根据上面的描述,可以知道,使用Mutex进行数据交互必须遵循以下原则:


  1. 所有操作数据的代码在执行之前必须首先尝试锁定同一个互斥量

  2. 只有在互斥量锁定成功的情况下才允许执行操作数据的代码

  3. 操作数据的代码执行以后,必须释放互斥量


如果在操作数据之前没有锁定互斥量的过程,或者锁定的是不同的互斥量,无论哪一种情况都达成不了同一时刻,只有一段代码执行的目标。


如果操作数据的代码执行之后没有释放互斥量,后续处理数据的代码将永远不能锁定互斥量,也就是说,后续的数据处理不能继续执行。


请按照上述原则在审视一下代码,主要关注mutex:


QMutex mutex;    
//define CreateDataTask class.
class CreateDataTask : public QThread
{
public:
   CreateDataTask(QMutex& mutex)
       :m_mutex(mutex)
  {
  }
private:
   QMutex& m_mutex;
   void run()
   {
       for(int i = 0; i < 10; ++i)
       {
           m_mutex.lock();
           cout << "WT:<<<<WriteData:" << i  
                             << "<<<<" << endl;
           WriteData();
           m_mutex.unlock();
       }
   }
};

::timeBeginPeriod(1);
//Create
thread object of CreateDataTask.
CreateDataTask *writer =
               
new CreateDataTask(mutex);
//Start Thread.
writer->start(QThread::NormalPriority);
for(int i = 0; i < 10; ++i)
{
   mutex.lock();
   cout << "RT:>>>>ReadData:" << i
                      << ">>>>" << endl;
   ReadData();
   data_array.clearData();
   mutex.unlock();
}

timeEndPeriod(1);


应该讲点原则


有一种说法,飞机是试飞员飞出来的,估计也会有很多人说,程序是程序员Debug出来的。这种观点作者实在是不敢苟同。多任务编程就是一个不能靠调试解决问题的例子。必须遵循上面的原则,否则的话程序的动作会有很大的不确定性。在开发的最后阶段,多任务相关的问题都会占有相当大的比例。那简直就是程序员的噩梦。


必须讲点原则。


写在文章的最后


既然已经读到这里了,拜托大家再用一分钟时间,将文章转发到各位的朋友圈,微信群中。


本公共号的成长需要您的支持!
阅读更多更新文章,请扫描下面二维码,关注微信公众号【面向对象思考】
EA&UML日拱一卒-多任务编程超入门-(7)关于mutex,你必须知道的