www.pudn.com > ThreadLibrary.zip > main.cpp


/** 
 *	@file 
 */ 
#include  
#include  
#include  
#include "ThreadLibrary\ThreadPool.h" 
#include "ThreadLibrary\CriticalSection.h" 
#include 		// For the random number 
#include 		// Random number seed 
 
 
CriticalSection coutGuard;		///< Guard the output so that it's not mishmashed by thread preemption 
CriticalSection statsGuard;		///< Ensure that the statistics are threadsafe! 
 
/** 
 *  Simple class to illustrate methods of population from within the thread pool... 
 */ 
struct ThreadStats 
{ 
	int commandExecutions;			///< Number of times the thread has executed a functor 
	int totalWaitTime;				///< Total length of time that the functors have had the thread waiting 
}; 
 
/** 
 *	Test request functor to illustrate how you override the operator() function, to perform its own action 
 */ 
class TestRequest : public ThreadRequest 
{ 
public: 
	/* 
	 *	@param requestNumber	Number of the functor 
	 *	@param stats			reference to the statistics structure that the functor will update 
	 */ 
	TestRequest(int requestNumber, std::map& stats) : number(requestNumber), stats(stats) 
	{ 
		srand(static_cast(time(0))); 
	} 
 
	void operator()(int threadId) throw() 
	{ 
		try 
		{ 
			// Do a random number wait...  
			int waitTime=0; 
			if(!(threadId % 10)) 
				waitTime = (rand() % 1000) + 3000; 
			else 
				waitTime = rand() % 1000; 
			::Sleep(waitTime);				// Wait up to 1 second before completing and 4 seconds on multiples of 10 
			 
			updateStats(threadId, waitTime); 
			Guard safeGuard(coutGuard); 
			std::cout << threadId << ": Request: " << number << " waited for " << waitTime << " milliseconds" << std::endl; 
		}	 
		catch(...) 
		{ 
			// Cannot allow the exception to propagate out 
		} 
	} 
 
private: 
	int number;								///< This functors unique number 
	std::map& stats;		///< reference to the global stats structure 
 
	/** 
	 *	Helper method to update the statistics map, ensuring that the integrity of the  
	 *  map is maintained using the statsGuard. 
	 *	@param threadId Id of the statistic structure to update 
	 *	@param waitTime Length of time this functor waited for 
	 */ 
	void updateStats(int threadId, int waitTime) 
	{ 
		Guard safeGuard(statsGuard); 
		if(stats.find(threadId)==stats.end()) 
		{ 
	        ThreadStats currentStat; 
			currentStat.commandExecutions = 1; 
			currentStat.totalWaitTime = waitTime; 
			stats.insert(std::make_pair(threadId, currentStat)); 
		} 
		else 
		{ 
			std::map::iterator item = stats.find(threadId); 
			(*item).second.commandExecutions++; 
			(*item).second.totalWaitTime += waitTime; 
		} 
	} 
	TestRequest(const TestRequest& copy); 
	TestRequest& operator=(const TestRequest& rhs); 
}; 
 
/** 
 * Derived thread class showing example of thread specific initialization and termination. 
 */ 
class COMPool : public ThreadPool 
{ 
public: 
	/** 
	 *	Start by initializing COM 
	 *	@param threadId Number of the thread 
	 */ 
	void onThreadStart(int threadId) 
	{ 
		Guard safeGuard(coutGuard); 
		std::cout << "Starting COM for thread " << threadId << std::endl; 
		::OleInitialize(NULL);	 
	} 
 
	/** 
	 *	Shutdown COM when we are finished 
	 *	@param threadId Number of the thread 
	 */ 
	void onThreadFinish(int threadId) 
	{ 
		Guard safeGuard(coutGuard); 
		std::cout << "Stopping COM for thread " << threadId << std::endl; 
		::OleUninitialize(); 
	} 
}; 
 
 
int main(int, char*) 
{ 
	COMPool myThread; 
	std::map stats; 
	myThread.accept(); 
 
	for(int j = 0 ; j < 200 ; ++j) 
	{ 
		int waitTime = rand() % 100; 
		::Sleep(waitTime);				// Wait up to 1 second before completing. 
		myThread.submitRequest(new TestRequest(j, stats)); 
	} 
	myThread.shutdown(); 
	 
	// Now output the results  
	for(std::map::const_iterator i = stats.begin() ; i != stats.end() ; ++i) 
		std::cout << "Thread Id: " << (*i).first << " executed " << (*i).second.commandExecutions << " times with total wait of " << (*i).second.totalWaitTime << std::endl; 
	return 0; 
}