Isis 3 Programmer Reference
CubeDataThreadTester.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "CubeDataThreadTester.h"
8 
9 #include <iostream>
10 
11 #include <QMap>
12 #include <QMutex>
13 #include <QReadWriteLock>
14 #include <QPair>
15 #include <QVector>
16 
17 #include "CubeDataThread.h"
18 #include "IString.h"
19 #include "FileName.h"
20 #include "Brick.h"
21 #include "Cube.h"
22 
23 using namespace std;
24 using namespace Isis;
25 
26 namespace Isis {
33  CubeDataThreadTester::CubeDataThreadTester(CubeDataThread *testObject) :
34  QThread() {
35  p_cachedDoneBricks = NULL;
36  p_cubeDataThread = testObject;
37  p_numTestsDone = 0;
38  p_execStarted = false;
39  p_notifyDone = true;
40 
42 
43  start();
44  moveToThread(this);
45  }
46 
47 
53  connect(this,
54  SIGNAL(RequestReadCube(int, int, int, int, int, int, void *)),
56  SLOT(ReadCube(int, int, int, int, int, int, void *)));
57 
58  connect(this,
59  SIGNAL(RequestReadWriteCube(int, int, int, int, int, int, void *)),
61  SLOT(ReadWriteCube(int, int, int, int, int, int, void *)));
62 
63  connect(this, SIGNAL(NotifyDoneWithData(int, const Isis::Brick *)),
64  p_cubeDataThread, SLOT(DoneWithData(int, const Isis::Brick *)));
65 
66  connect(p_cubeDataThread, SIGNAL(ReadReady(void *, int, const Isis::Brick *)),
67  this, SLOT(ReadBrick(void *, int, const Isis::Brick *)));
68 
69  connect(p_cubeDataThread, SIGNAL(ReadWriteReady(void *, int, Isis::Brick *)),
70  this, SLOT(ReadWriteBrick(void *, int, Isis::Brick *)));
71  }
72 
73 
79  if(!p_execStarted) {
80  QThread::yieldCurrentThread();
81  }
82 
83  QThread::exit(0);
84 
85  wait();
86  }
87 
90  p_execStarted = true;
91  exec();
92  }
93 
100  cout << "=============== Testing Basic Read ===============" << endl;
101  emit RequestReadCube(cubeId, 1, 1, 2, 2, 1, this);
102  }
103 
104 
111  void CubeDataThreadTester::ReadCubeTest2(int cubeId1, int cubeId2) {
112  cout << "=============== Testing Multiple Non-Conflicting Cube Reads " <<
113  "===============" << endl;
114 
115  p_notifyDone = false;
116  emit RequestReadCube(cubeId1, 1, 1, 3, 2, 1, this);
117  emit RequestReadCube(cubeId2, 1, 2, 3, 2, 1, this);
118  }
119 
120 
127  cout << "=============== Testing Exact Overlap Cube Reads ==============="
128  << endl << endl;
129 
130  p_notifyDone = false;
131  emit RequestReadCube(cubeId, 1, 2, 2, 2, 1, this);
132  emit RequestReadCube(cubeId, 1, 2, 2, 2, 1, this);
133  }
134 
135 
142  cout << "=============== Testing Basic R/W ===============" << endl << endl;
143  emit RequestReadWriteCube(cubeId, 1, 1, 2, 2, 1, this);
144  emit RequestReadCube(cubeId, 1, 1, 2, 2, 1, this);
145  }
146 
147 
154  void CubeDataThreadTester::WriteCubeTest2(int cubeId1, int cubeId2) {
155  cout << "=============== Testing Multiple Non-Conflicting Cube R/W " <<
156  "===============" << endl << endl;
157 
158  p_notifyDone = false;
159  emit RequestReadWriteCube(cubeId1, 1, 1, 3, 1, 1, this);
160  emit RequestReadWriteCube(cubeId2, 1, 1, 3, 1, 1, this);
161  }
162 
163 
173  cout << "=============== Testing Conflicting Cube R/W ==============="
174  << endl;
175 
176  p_notifyDone = false;
177  emit RequestReadWriteCube(cubeId, 1, 1, 3, 1, 1, this);
178  emit RequestReadWriteCube(cubeId, 1, 1, 3, 1, 1, this);
179  }
180 
181 
187  cout << " Breaking Deadlock From Test 3" << endl;
188  while(!p_cachedDoneBricks->size()) {
189  msleep(100);
190  }
191 
192  if(p_cachedDoneBricks->size()) {
193  cout << " Notify done with first brick" << endl;
194  emit NotifyDoneWithData((*p_cachedDoneBricks)[0].first,
195  (*p_cachedDoneBricks)[0].second);
196  p_cachedDoneBricks->clear();
197  }
198  }
199 
200 
207  cout << "=============== Testing Change Notification ==============="
208  << endl;
209 
210  connect(p_cubeDataThread,
211  SIGNAL(BrickChanged(int, const Isis::Brick *)),
212  this,
213  SLOT(BrickChanged(int, const Isis::Brick *))
214  );
215 
217  emit RequestReadWriteCube(cubeId, 5, 1, 5, 1, 1, this);
218  }
219 
220 
228  void CubeDataThreadTester::ReadBrick(void *requester, int cubeId,
229  const Isis::Brick *data) {
230  cout << " CubeDataThreadTester::ReadBrick" << endl;
231 
232  cout << " Requester is me? " << ((this == requester) ? "Yes" : "No")
233  << endl;
234 
235  if(this != requester) return;
236 
237  cout << " Data:" << endl;
238 
239  for(int i = 0; i < data->size(); i++) {
240  if(i == 0) cout << " ";
241  if(i % 6 == 6 - 1 && i != data->size() - 1) {
242  cout << data->at(i) << endl << " ";
243  }
244  else if(i == data->size() - 1) {
245  cout << data->at(i) << endl;
246  }
247  else {
248  cout << data->at(i) << "\t";
249  }
250  }
251 
252  cout << endl;
253  if(p_notifyDone) {
254  cout << " Notify done with this brick" << endl;
255  emit NotifyDoneWithData(cubeId, data);
256 
257  if(p_cachedDoneBricks->size()) {
258  cout << " Notify done with first brick" << endl;
259  emit NotifyDoneWithData((*p_cachedDoneBricks)[0].first,
260  (*p_cachedDoneBricks)[0].second);
261  p_cachedDoneBricks->clear();
262  }
263  }
264  else {
266  cache.first = cubeId;
267  cache.second = data;
268 
269  p_cachedDoneBricks->push_back(cache);
270  }
271 
272  p_notifyDone = true;
273  p_numTestsDone ++;
274  }
275 
283  void CubeDataThreadTester::ReadWriteBrick(void *requester, int cubeId,
284  Isis::Brick *data) {
285  cout << " CubeDataThreadTester::ReadWriteBrick" << endl;
286 
287  // This was a nice idea, but has race conditions that are difficult
288  // at best to resolve.
289 
290  //cout << " Managed Bricks in Memory = " <<
291  // p_cubeDataThread->BricksInMemory() << endl;
292 
293  cout << " Changing Brick : Index 0 Becoming 5" << endl;
294  cout << endl;
295 
296  cout << " Old Data: " << endl;
297 
298  for(int i = 0; i < data->size(); i++) {
299  if(i == 0) cout << " ";
300  if(i % 6 == 6 - 1 && i != data->size() - 1) {
301  cout << data->at(i) << endl << " ";
302  }
303  else if(i == data->size() - 1) {
304  cout << data->at(i) << endl;
305  }
306  else {
307  cout << data->at(i) << "\t";
308  }
309  }
310 
311  (*data)[0] = 5;
312 
313  cout << " New Data: " << endl;
314 
315  for(int i = 0; i < data->size(); i++) {
316  if(i == 0) cout << " ";
317  if(i % 6 == 6 - 1 && i != data->size() - 1) {
318  cout << data->at(i) << endl << " ";
319  }
320  else if(i == data->size() - 1) {
321  cout << data->at(i) << endl;
322  }
323  else {
324  cout << data->at(i) << "\t";
325  }
326  }
327 
328  cout << endl;
329 
330  if(p_notifyDone) {
331  cout << " Notify done with this brick" << endl;
332  emit NotifyDoneWithData(cubeId, data);
333 
334  if(p_cachedDoneBricks->size()) {
335  cout << " Notify done with first brick" << endl;
336  emit NotifyDoneWithData((*p_cachedDoneBricks)[0].first,
337  (*p_cachedDoneBricks)[0].second);
338  p_cachedDoneBricks->clear();
339  }
340  }
341  else {
343  cache.first = cubeId;
344  cache.second = data;
345 
346  p_cachedDoneBricks->push_back(cache);
347  }
348 
349  p_notifyDone = true;
350  p_numTestsDone ++;
351  }
352 
353 
360  void CubeDataThreadTester::BrickChanged(int cubeId, const Isis::Brick *data) {
361  cout << " CubeDataThreadTester::BrickChanged" << endl;
362  cout << " Data:" << endl;
363 
364  for(int i = 0; i < data->size(); i++) {
365  if(i == 0) cout << " ";
366  if(i % 6 == 6 - 1 && i != data->size() - 1) {
367  cout << data->at(i) << endl << " ";
368  }
369  else if(i == data->size() - 1) {
370  cout << data->at(i) << endl;
371  }
372  else {
373  cout << data->at(i) << "\t";
374  }
375  }
376 
377  p_numTestsDone ++;
378  emit NotifyDoneWithData(cubeId, data);
379  }
380 };
Isis::CubeDataThreadTester::p_numTestsDone
int p_numTestsDone
The count of completed tests.
Definition: CubeDataThreadTester.h:99
Isis::CubeDataThreadTester::p_cubeDataThread
CubeDataThread * p_cubeDataThread
The data thread being tested.
Definition: CubeDataThreadTester.h:102
Isis::CubeDataThreadTester::BrickChanged
void BrickChanged(int cubeId, const Isis::Brick *data)
This is called when a brick is written.
Definition: CubeDataThreadTester.cpp:360
Isis::CubeDataThreadTester::run
void run()
This thread is centered completely around its event loop.
Definition: CubeDataThreadTester.cpp:89
Isis::CubeDataThreadTester::ReadCubeTest2
void ReadCubeTest2(int, int)
This tests two basic reads with no conflicts.
Definition: CubeDataThreadTester.cpp:111
Isis::CubeDataThreadTester::RequestReadCube
void RequestReadCube(int cubeId, int startSample, int startLine, int endSample, int endLine, int band, void *caller)
Ask for a brick for reading.
Isis::CubeDataThreadTester::NotifyDoneWithData
void NotifyDoneWithData(int, const Isis::Brick *)
Let the cube data thread know we're no longer working with a particular brick.
Isis::CubeDataThreadTester::p_cachedDoneBricks
QVector< QPair< int, const Isis::Brick * > > * p_cachedDoneBricks
A list of bricks we haven't send the done signal for.
Definition: CubeDataThreadTester.h:111
Isis::CubeDataThreadTester::ReadCubeTest
void ReadCubeTest(int)
This tests a basic read.
Definition: CubeDataThreadTester.cpp:99
Isis::Brick
Buffer for containing a three dimensional section of an image.
Definition: Brick.h:45
Isis::CubeDataThreadTester::WriteCubeTest
void WriteCubeTest(int)
This tests a basic write.
Definition: CubeDataThreadTester.cpp:141
Isis::CubeDataThread
Encapsulation of Cube I/O with Change Notifications.
Definition: CubeDataThread.h:59
Isis::CubeDataThread::AddChangeListener
void AddChangeListener()
You must call this method after connecting to the BrickChanged signal, otherwise you are not guarante...
Definition: CubeDataThread.cpp:230
Isis::CubeDataThreadTester::p_notifyDone
bool p_notifyDone
True if we will notify done on the next brick received for R/W.
Definition: CubeDataThreadTester.h:108
Isis::CubeDataThreadTester::~CubeDataThreadTester
virtual ~CubeDataThreadTester()
This cleans up the cube data thread.
Definition: CubeDataThreadTester.cpp:78
Isis::CubeDataThreadTester::NotifyChangeTest
void NotifyChangeTest(int)
This test tests this automatic change notifications.
Definition: CubeDataThreadTester.cpp:206
Isis::CubeDataThreadTester::ReadCubeTest3
void ReadCubeTest3(int)
This tests an overlapping read.
Definition: CubeDataThreadTester.cpp:126
Isis::CubeDataThreadTester::p_execStarted
bool p_execStarted
True if this thread is started.
Definition: CubeDataThreadTester.h:105
Isis::Buffer::at
double at(const int index) const
Returns the value in the shape buffer at the given index.
Definition: Buffer.cpp:231
Isis::CubeDataThreadTester::ReadWriteBrick
void ReadWriteBrick(void *requester, int cubeId, Isis::Brick *data)
This is called when a brick is given for R/W.
Definition: CubeDataThreadTester.cpp:283
Isis::CubeDataThreadTester::WriteCubeTest3BreakDeadlock
void WriteCubeTest3BreakDeadlock()
This test breaks the deadlock caused by the third write test.
Definition: CubeDataThreadTester.cpp:186
std
Namespace for the standard library.
QThread
QPair
This is free and unencumbered software released into the public domain.
Definition: CubeIoHandler.h:23
Isis::Buffer::size
int size() const
Returns the total number of pixels in the shape buffer.
Definition: Buffer.h:97
QVector
This is free and unencumbered software released into the public domain.
Definition: Calculator.h:18
Isis::CubeDataThreadTester::ReadBrick
void ReadBrick(void *requester, int cubeId, const Isis::Brick *data)
This is called when a brick is read.
Definition: CubeDataThreadTester.cpp:228
Isis::CubeDataThreadTester::Connect
void Connect()
This connects this class' signals and slots with CubeDataThread's signals and slots.
Definition: CubeDataThreadTester.cpp:52
Isis::CubeDataThreadTester::RequestReadWriteCube
void RequestReadWriteCube(int cubeId, int startSample, int startLine, int endSample, int endLine, int band, void *caller)
Ask for a brick for reading and writing.
Isis::CubeDataThreadTester::WriteCubeTest2
void WriteCubeTest2(int, int)
This tests two non-conflicting writes.
Definition: CubeDataThreadTester.cpp:154
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::CubeDataThreadTester::WriteCubeTest3
void WriteCubeTest3(int)
This tests two conflicting* writes.
Definition: CubeDataThreadTester.cpp:172