Browse Source

Fixed potential race condition where the ExecutiveProcess might send a notification message through cout while the OutputProcessor was busy using cout also. The result would be (at best) corrupted output. Now the ExecutiveProcess and the OutputProcessor both use OutputProcessor::sendString() which protects cout with a mutex.

git-svn-id: https://svn.microneil.com/svn/SNF4CGP/trunk@34 59e8e3e7-56fa-483b-b4b4-fa6ab0af3dfc
master
madscientist 15 years ago
parent
commit
1f9713514c

+ 17
- 4
SNF4CGP/ExecutiveProcess.cpp View File

#include "../CodeDweller/faults.hpp" #include "../CodeDweller/faults.hpp"
#include <iostream> #include <iostream>
#include <string>
#include <sstream>
using namespace std; using namespace std;
dispatchCommand(C); // and dispatch a job with it. dispatchCommand(C); // and dispatch a job with it.
} }
void ExecutiveProcess::notifyQUIT() {
ostringstream O;
O << "* SNF4CGP[" << QuitJobNumber << "] Received QUIT, shutting down..." << endl;
Output.sendString(O.str());
}
void ExecutiveProcess::notifyNOTGOOD() {
ostringstream O;
O << "* SNF4CGP Input stream has gone bad, shutting down..." << endl;
Output.sendString(O.str());
}
void ExecutiveProcess::doProcessing() { // Command processing happens here. void ExecutiveProcess::doProcessing() { // Command processing happens here.
dispatchWakeupCommand(); // First job is to announce ourselves. dispatchWakeupCommand(); // First job is to announce ourselves.
for(;;) { // Then process all jobs but QUIT. for(;;) { // Then process all jobs but QUIT.
case Command::QUIT: { case Command::QUIT: {
QuitJobNumber = C.Number; QuitJobNumber = C.Number;
cout << "* SNF4CGP[" << C.Number << "] Received QUIT, shutting down..." << endl;
cout.flush();
notifyQUIT();
return; return;
} }
case Command::NOTGOOD: { case Command::NOTGOOD: {
cout << "* SNF4CGP Input stream has gone bad, shutting down..." << endl;
cout.flush();
notifyNOTGOOD();
return; return;
} }
default: { default: {
dispatchCommand(C); dispatchCommand(C);
continue;
} }
} }
} }

+ 3
- 0
SNF4CGP/ExecutiveProcess.hpp View File

void dispatchCommand(Command& C); // Job + Worker + Command; go! void dispatchCommand(Command& C); // Job + Worker + Command; go!
void dispatchWakeupCommand(); void dispatchWakeupCommand();
void notifyQUIT();
void notifyNOTGOOD();
public: public:
ExecutiveProcess(const string& Version, const string& Config); // Simple construction. The d'tor needs ExecutiveProcess(const string& Version, const string& Config); // Simple construction. The d'tor needs

+ 7
- 2
SNF4CGP/OutputProcessor.cpp View File

CompletedJobs.give(&J); CompletedJobs.give(&J);
} }
void OutputProcessor::sendString(const string& S) { // Safely send a string to cout.
ScopeMutex OneFlushAtATime(ProtectCout);
cout << S;
cout.flush();
}
void OutputProcessor::stop() { // Finish off the queue and quit. void OutputProcessor::stop() { // Finish off the queue and quit.
if(false == isTimeToStop) { // Do this only once. if(false == isTimeToStop) { // Do this only once.
isTimeToStop = true; // Set the stop flag. isTimeToStop = true; // Set the stop flag.
void OutputProcessor::handleJob(Job& J) { // Process a job. void OutputProcessor::handleJob(Job& J) { // Process a job.
CurrentThreadState(PostingResponses); CurrentThreadState(PostingResponses);
cout << J.Responses();
cout.flush();
sendString(J.Responses());
J.clear(); J.clear();
RecycledJobs().drop(J); RecycledJobs().drop(J);
} }

+ 3
- 0
SNF4CGP/OutputProcessor.hpp View File

class OutputProcessor : private Thread { // Process job outputs. class OutputProcessor : private Thread { // Process job outputs.
private: private:
Mutex ProtectCout;
JobPool* RecycledJobs_; // Where we put our recycled jobs. JobPool* RecycledJobs_; // Where we put our recycled jobs.
JobPool& RecycledJobs(); // Safe access to jobs pool. JobPool& RecycledJobs(); // Safe access to jobs pool.
ProductionQueue<Job*> CompletedJobs; // Input queue for jobs to process. ProductionQueue<Job*> CompletedJobs; // Input queue for jobs to process.
void init(JobPool& J); // Start processing. void init(JobPool& J); // Start processing.
void outputJob(Job& J); // Take this job and ... you know. void outputJob(Job& J); // Take this job and ... you know.
void sendString(const string& S); // Safely send a string to cout.
void stop(); // Finish off the queue and quit. void stop(); // Finish off the queue and quit.
const static ThreadType Type; const static ThreadType Type;

+ 1
- 1
SNF4CGP/main.cpp View File

using namespace std; // Introduce standard namespace. using namespace std; // Introduce standard namespace.
const string SNF4CGP_VERSION_INFO = "SNF4CGP Version 0.0.2 Build: " __DATE__ " " __TIME__;
const string SNF4CGP_VERSION_INFO = "SNF4CGP Version 0.0.3 Build: " __DATE__ " " __TIME__;
const int ConfigPathArgNumber = 1; const int ConfigPathArgNumber = 1;
const int CorrectArgcNumber = 2; const int CorrectArgcNumber = 2;

Loading…
Cancel
Save