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
23using namespace std;
24using namespace Isis;
25
26namespace Isis {
34 QThread() {
35 p_cachedDoneBricks = NULL;
36 p_cubeDataThread = testObject;
38 p_execStarted = false;
39 p_notifyDone = true;
40
41 p_cachedDoneBricks = new QVector< QPair<int, const Isis::Brick *> >;
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 {
265 QPair<int, const Brick *> cache;
266 cache.first = cubeId;
267 cache.second = data;
268
269 p_cachedDoneBricks->push_back(cache);
270 }
271
272 p_notifyDone = true;
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 {
342 QPair<int, const Brick *> cache;
343 cache.first = cubeId;
344 cache.second = data;
345
346 p_cachedDoneBricks->push_back(cache);
347 }
348
349 p_notifyDone = true;
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
378 emit NotifyDoneWithData(cubeId, data);
379 }
380};
Buffer for containing a three dimensional section of an image.
Definition Brick.h:45
int size() const
Returns the total number of pixels in the shape buffer.
Definition Buffer.h:97
double at(const int index) const
Returns the value in the shape buffer at the given index.
Definition Buffer.cpp:231
Encapsulation of Cube I/O with Change Notifications.
void AddChangeListener()
You must call this method after connecting to the BrickChanged signal, otherwise you are not guarante...
bool p_notifyDone
True if we will notify done on the next brick received for R/W.
void Connect()
This connects this class' signals and slots with CubeDataThread's signals and slots.
void RequestReadWriteCube(int cubeId, int startSample, int startLine, int endSample, int endLine, int band, void *caller)
Ask for a brick for reading and writing.
void ReadCubeTest(int)
This tests a basic read.
void ReadBrick(void *requester, int cubeId, const Isis::Brick *data)
This is called when a brick is read.
void WriteCubeTest(int)
This tests a basic write.
int p_numTestsDone
The count of completed tests.
void WriteCubeTest2(int, int)
This tests two non-conflicting writes.
CubeDataThread * p_cubeDataThread
The data thread being tested.
bool p_execStarted
True if this thread is started.
void ReadCubeTest3(int)
This tests an overlapping read.
void NotifyChangeTest(int)
This test tests this automatic change notifications.
virtual ~CubeDataThreadTester()
This cleans up the cube data thread.
void run()
This thread is centered completely around its event loop.
CubeDataThreadTester(CubeDataThread *)
This initializes a CubeDataThreadTester.
void ReadCubeTest2(int, int)
This tests two basic reads with no conflicts.
void WriteCubeTest3(int)
This tests two conflicting* writes.
void WriteCubeTest3BreakDeadlock()
This test breaks the deadlock caused by the third write test.
QVector< QPair< int, const Isis::Brick * > > * p_cachedDoneBricks
A list of bricks we haven't send the done signal for.
void RequestReadCube(int cubeId, int startSample, int startLine, int endSample, int endLine, int band, void *caller)
Ask for a brick for reading.
void ReadWriteBrick(void *requester, int cubeId, Isis::Brick *data)
This is called when a brick is given for R/W.
void NotifyDoneWithData(int, const Isis::Brick *)
Let the cube data thread know we're no longer working with a particular brick.
void BrickChanged(int cubeId, const Isis::Brick *data)
This is called when a brick is written.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
Namespace for the standard library.