EA&UML日拱一卒-多任务编程超入门-(3)线程协作的理想和现实
为什么需要协作?
一般说来,只要存在多任务,就需要任务之间的协作。这里的协作包含数据交换和任务同步。
数据交换很简单,就是进程或线程之间数据的传递,可能是一方生成数据,另外一方使用数据;也可能多方生成数据,多方使用数据等。
同步是进程或线程之间的步调的调整,例如通讯线程生成数据以后,控制线程才开始工作;或者所有线程都结束以后,应用程序进程才结束等。
我们当然希望线程之间的协作是在编程者不知情的情况下实现的,这可以说是多线程变成的理想状态,但现实呢?
线程间通讯实例
我们用一个例子来说明。这个例子稍微有些复杂,但是难度并不高,安下心来看下去即可。
数据类DataArray
#ifndef DATAARRAY_H
#define DATAARRAY_H
#define ARRAY_SIZE 500
class DataArray
{
protected:
int m_buffer[ARRAY_SIZE];
int m_dataSize;
public:
DataArray();
int getDataSize();
int getData(int index);
int addData(int data);
void clearData();
};
#endif // DATAARRAY_H
这个类用于数据生成模块和使用数据模块之间传递数据,除了构造函数以外这个类一共有四个方法:
-
getDataSize:取得数组中保存数据的数量
-
getData:指定索引值取数据
-
addData:在数组的最后添加数据
-
clearData:清除所有数据。
以下是实现代码:
#include "dataarray.h"
#include <iostream>
using namespace std;
DataArray::DataArray()
:m_dataSize(0)
{
}
int DataArray::getDataSize()
{
return m_dataSize;
}
int DataArray::getData(int index)
{
if(index >= 0 && index < m_dataSize)
{
return m_buffer[index];
}
else
{
return -1;
}
}
int DataArray::addData(int data)
{
if(m_dataSize < (ARRAY_SIZE - 1))
{
m_buffer[m_dataSize] = data;
m_dataSize++;
}
return true;
}
void DataArray::clearData()
{
m_dataSize = 0;
}
数据类DataArray的实现非常简单,大家可以自己看一下。
另外为了简化利用侧的代码,另外准备了两个简单的C函数。
void WriteData(int base)
{
for(int j = 0; j < 5; ++j)
{
data_array.addData(j);
}
}
WriteData连续写入5个数据,分别是0,1,2,3,4.
void ReadData()
{
int data_size = data_array.getDataSize();
int total = 0;
for(int k = 0; k < data_size; ++k)
{
total += data_array.getData(k);
}
cout << "RT:----total=" << total << endl;
}
ReadData从缓冲区中读出数据并求和.
单任务条件下的执行情况
可以通过一段小程序调用上述两个函数。
for(int i = 0; i < 10; ++i)
{
cout << "WT:<<<<WriteData:" << i << "<<<<" << endl;
WriteData(i);
cout << "RT:>>>>ReadData:" << i << ">>>>" << endl;
ReadData();
data_array.clearData();
}
以下是执行结果
WT:<<<<WriteData:0<<<<
RT:>>>>ReadData:0>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:1<<<<
RT:>>>>ReadData:1>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:2<<<<
RT:>>>>ReadData:2>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:3<<<<
RT:>>>>ReadData:3>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:4<<<<
RT:>>>>ReadData:4>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:5<<<<
RT:>>>>ReadData:5>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:6<<<<
RT:>>>>ReadData:6>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:7<<<<
RT:>>>>ReadData:7>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:8<<<<
RT:>>>>ReadData:8>>>>
RT::----data_size=5
RT:----total=10
WT:<<<<WriteData:9<<<<
RT:>>>>ReadData:9>>>>
RT::----data_size=5
RT:----total=10
可以看到,读写操作分别执行10次,每次取得的数据都是5个,求和结果都是10.
多任务条件下的执行情况
示例代码
//define CreateDataTask class.
class CreateDataTask : public QThread
{
void run()
{
for(int i = 0; i < 10; ++i)
{
cout << "WT:<<<<WriteData:" << i << "<<<<" << endl;
WriteData(i);
}
}
};
//Create thread object of CreateDataTask.
CreateDataTask *writer = new CreateDataTask();
//Start Thread.
writer->start(QThread::NormalPriority);
for(int i = 0; i < 10; ++i)
{
cout << "RT:>>>>ReadData:" << i << ">>>>" << endl;
ReadData();
data_array.clearData();
}
首先定义一个CreateDataTask类,它的成员函数run的内容是执行10次写数据函数WriteData。这里只是定义CreateDataTask类,就像定义函数一样。
接下来创建CreateDataTask对象并执行。start方法被调用之后,CreateDataTask线程开始执行。
最后接下来调用10次读数据函数,每次调用读数据函数以后也会清除数据。
以下是程序执行以后的输出结果:
RT:>>>>ReadData:WT:<<<<WriteData:0<<<<
WT:<<<<WriteData:1<<<<
WT:<<<<WriteData:20>>>>
RT::----data_size=10
RT:----total=20
RT:>>>>ReadData:1>>>>
RT::----data_size=0
RT:----total=0
RT:>>>>ReadData:2>>>>
RT::----data_size=0
RT:----total=0
RT:>>>>ReadData:3>>>>
RT::----data_size=0
RT:----total=0
RT:>>>>ReadData:4>>>>
RT::----data_size=0
RT:----total=0
RT:>>>>ReadData:5>>>>
RT::----data_size=0
RT:----total=0
RT:>>>>ReadData:6>>>>
RT::----data_size=0
RT:----total=0
RT:>>>>ReadData:7>>>>
RT::----data_size=0
RT:----total=0
RT:>>>>ReadData:8>>>>
RT::----data_size=0
RT:----total=0
RT:>>>>ReadData:9>>>>
RT::----data_size=0
RT:----total=0
<<<<
WT:<<<<WriteData:3<<<<
WT:<<<<WriteData:4<<<<
WT:<<<<WriteData:5<<<<
WT:<<<<WriteData:6<<<<
WT:<<<<WriteData:7<<<<
WT:<<<<WriteData:8<<<<
WT:<<<<WriteData:9<<<<
从输出结果可以看出:读,写函数执行的先后顺序不定;读出的数据个数,求和结果有经常会发生错误。如果多次执行的话,会的到许多不同的结果。
为了获得快速响应而导入了多线程,但是结果并不是我们想要的,这是为什么呢?
且听下回分解。
示例代码下载链接:
本连载示例代码可以在QT环境下运行,请从以下链接下载:
http://download.****.net/detail/craftsman1970/9893127
写在文章的最后
既然已经读到这里了,拜托大家再用一分钟时间,将文章转发到各位的朋友圈,微信群中。