爲什麼需要協作?
一般說來,只要存在多任務,就需要任務之間的協作。這裏的協作包含數據交換和任務同步。
數據交換很簡單,就是進程或線程之間數據的傳遞,可能是一方生成數據,另外一方使用數據;也可能多方生成數據,多方使用數據等。
同步是進程或線程之間的步調的調整,例如通訊線程生成數據以後,控制線程纔開始工作;或者所有線程都結束以後,應用程序進程才結束等。
我們當然希望線程之間的協作是在編程者不知情的情況下實現的,這可以說是多線程變成的理想狀態,但現實呢?
線程間通訊實例
我們用一個例子來說明。這個例子稍微有些複雜,但是難度並不高,安下心來看下去即可。
數據類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.csdn.net/detail/craftsman1970/9893127
寫在文章的最後
既然已經讀到這裏了,拜託大家再用一分鐘時間,將文章轉發到各位的朋友圈,微信羣中。