SourceForge.net Logo

MSDK 2.11

Copyright 2004-2006, Zlatko Michailov




License

Support

How to Use
         Platform Requirements
         Installation
         Compilation
         Building Samples

Content
         What's New In MSDK 2.11
         What's New In MSDK 2.10
         What's New In MSDK 2.01

         Primitives
                  Mutex
                  Event
                  Blocking Counter
                  Semi-Mutex

         Thread Support
                  Message
                  MessagePayload
                  Blocking Sequence
                  Thread
                  Buffer
                  Utilities

         Process Support
                  Log
                  LogMessagePayload
                  Config
                  Service

         Multithreading Applications
                  Single Writer - Multiple Readers
                  Thread Pool

         Samples
                  readwrite
                  async-threadpool
                  async-bqueue
                  log
                  config
                  service




License

MSDK contains original C++ source code and documentation written by Zlatko Michailov. All copyrights belong to Zlatko Michailov. MSDK is distributed under the BSD License.



Support

MSDK is an Open Source project. To receive or provide support, please visit the MSDK Project Home.



How to Use

         Platform Requirements

MSDK supports the 32-bit Windows platform at two levels: Win32 API and Microsoft Visual C++ Run-Time library (MSVCRT). Some process-related feature require CRT. UNIX platforms are supported at the level of the Pthread library.


         Installation

Extract the contents of the archive to a directory of your choice. No files are copied outside the target directory. There are no side effects to the operating system. Multiple version of MSDK can co-exist on the same machine. To uninstall MSDK, delete the installation directory. MSDK is only needed for compiling your applications. MSDK is not needed at execution time.


         Compilation

MSDK chooses an underlying library based on the existence of the following preprocessor definitions: To use the MSDK, include the root header file, msdk.h, from the installation directory, e.g. if MSDK is installed in directory ../msdk:
         #include "../msdk/msdk.h"

msdk.h includes the rest of MSDK.

On UNIX platforms you have to add the following libraries to link against: /usr/lib/libstdc++.so.5 and /usr/lib/libpthread.so. Versions might be different.


         Building Samples

There are two make files one for Windows and one for UNIX. To build the samples, navigate to the samples subdirectory and execute the following command:
WIN32 nmake -f makefile-win
UNIX  make -f makefile-unix




Content

All MSDK classes belong to namespace msdk. You should either prepend each class name with msdk:: or you should have the following statement:
         using namespace msdk;

Starting with MSDK 2.10 a new, nested namespace is added msdk::process for process-related functionality.


         What's New In MSDK 2.11

MSDK 2.11 is a maintenance release over MSDK 2.10. It's purpose is to improve the existing baseline and to prepare it for the new features that are already under discussion.

Recently the license was changed was changed to BSD which is allows much more freedom to the developer than the prevously used LGPL, and GPL.

The following fixes are included in MSDK 2.11:

         What's New In MSDK 2.10

MSDK 2.10 adds support for complete multithreaded applications - logging, configration manipulation, and service skeleton. The process support sits on top of the core MSDK. Hence, the code rsides in a nested namespace - msdk::process. Adding an extra level to MSDK involved more rigorous testing of the core and some enhancements were made without breaking backward compatibility.


                  Enhancements to Exisitng Classes
                  Additions

         What's New In MSDK 2.01

The new features of MSDK 2.01 target thread initialization. In MSDK 2.00 a ThreadPool instance could only create Thread instances using the default constructor. Thus the pool was not able to pass any initialization data before the threads start. MSDK 2.01 enhances the thread initialization process as follows:

         Primitives

                  Mutex

Mutex is a standard synchronization primitive. It may be acquired (locked) by no more than one thread at a time. Subsequent acquisition attempts cause the calling thread to be blocked without consuming CPU. When a mutex is released (unlocked), a blocked thread is chosen randomly to acquire the mutex. The MSDK implementation of the mutex primitive allows one thread to acquire a mutex multiple times (recursively). To release the mutex, the thread is requied to unlock it the same number of times.

Public methods of class msdk::Mutex:
         bool Lock() - Attempts to acquire the mutex. Returns true on success, false on failure.
         bool Unlock() - Attempts to release the mutex. Returns true on success, false on failure.
WIN32 operator HANDLE() - Returns the HANDLE of the Win32 mutex object to be used in other Win32 API calls.
UNIX  operator pthread_mutex_t*() - Returns the pthread_mutext_t* of the Pthread mutex object to be used in other Pthread API calls.


                  Event

Event is also a standard synchronization primitive. It may be waited on or explicitly signaled. After construction an event instance is non-signaled, i.e. waiting is enabled. The MSDK implementation supports three types of signaling:
Public methods of class msdk::Event:
         bool Wait() - Attempts to wait on the event infinitely. Returns true on success, false on failure.
         bool Signal( SignalType signal = SIGNAL) - Attempts to signal the event. Possible signal types are PULSE, SIGNAL, and PERMANENT. Returns true on success, false on failure.
         bool Reset() - Attempts to reset the event as non-signaled. Returns true on success, false on failure.
WIN32 operator HANDLE() - Returns the HANDLE of the Win32 event object to be used in other Win32 API calls.
UNIX  operator pthread_cond_t*() - Returns the pthread_cond_t* of the Pthread event object to be used in other Pthread API calls.


                  Blocking Counter

Blocking counter is a new synchronization primitive introduced in MSDK. It allows to incremented and decremented without blocking as long as the value remains non-negative. This means it could be incremented at any time without waiting. When a decrement attempt is made, if the value is positive, the counter is decremented. If the value is 0, the calling thread is blocked until some other thread increments the counter. This implementation of the blocking counter supports only incrementing/decrementing by 1, and a blocking counter is always initialized to 0. A blocking counter instance signals two events: Clear, when the counter value becomes 0; and Dirty, when the counter value changes from 0 to non-zero.

The blocking counter primitive becomes very useful when it is embedded in more complex objects. For instance, a blocking queue (see Thread Support) allows pushing at any time and popping only when there are items in the queue. Pushing maps to incrementing a blocking counter, and popping maps to decrementing. This makes the blocking queue implementation straightforward.

Public methods of class msdk::BlockingCounter:
         int Value() - Returns the value of the counter.
         bool IsClear() - Returns true if the value of the counter is 0 (clear), false otherwise.
         bool WaitUntilClear() - Blocks the calling thread until the value of the counter is clear. If the value is already clear, the method returns immediately. Returns true on successful wait, false on wait failure.
         bool WaitUntilDirty() - Blocks the calling thread until the value of the counter is dirty (non-zero). If the value is already dirty, the method returns immediately. Returns true on successful wait, false on wait failure. Both Clear and Dirty event are signaled permanently. This means hat more than one thread may be released at the same time. If exclusive access is needed, special care should be taken like in the implementation of the BlockingDecrement() method.
         bool Increment() - Increments the value of the counter by 1 without blocking. Returns true on success, false on failure.
         bool BlockingDecrement() - Decrements the value of the counter. If the value is dirty, does not block. If the value is clear, blocks the calling thread until the value becomes dirty. Returns true on success, false on failure.
         BlockingCounter& operator++() - Shortcut to Increment().
         BlockingCounter& operator--() - Shortcut to BlockingDecrement().


                  Semi-Mutex

Semi-Mutex is another synchronization primitive introduced in MSDK. It supports the same exclusive locking functionality as the standard mutex, plus an extra pair of methods for shared locking. Unlimited number of threads are allowed to hold a shared lock while no exclusive lock is held on the same semi-mutex instance. When a thread attempts to lock a semi-mutex exclusively, all further shared lock attempts are blocked until the thread with the exclusive lock releases the lock. The thread that attempts to lock exclusively waits for all threads that are currently holding shared locks to release their locks. A semi-mutex makes the implementation of a common single-writer-multiple-readers workflow straightforward.

Public methods of class msdk::SemiMutex:
         bool ReadLock() - Obtains a shared lock. If there is a thread holding an exclusive lock, the calling thread is blocked until the exclusive lock is released. Otherwise the method returns without blocking. Subsequent attempts to obtain an exclusive lock will be blocked until all shared locks are released. Returns true on success, false on failure.
         bool ReadUnlock() - Releases a shared lock. Does not block. Returns true on success, false on failure.
         bool Lock() - Obtains an exclusive lock. If there are currently shared locks or another exclusive lock, the calling thread is blocked until all locks are released. All subsequent attempts to obtain any lock are blocked until the calling thread releases its exclusive lock. Returns true on success, false on failure.
         bool Unlock() - Releases an exclusive lock. Returns true on success, false on failure.


         Thread Support

Both Win32 API and the Pthread library expose sufficient functionalities for thread support. However, they follow different paradigms and neither of them is wrapped by C++ classes. The MSDK thread support classes unify the essential functionality through platform-independent C++ classes.

                  Message

Message is a thread-support primitive that carries a command and a data buffer. In Windows messages may carry a command and up to two 32-bit integer parameters. In UNIX such a feature doesnt exist at all. Class msdk::Message provides convenient constructors optimized for performance. There are three options to construct a Message instance from a data buffer:
Public members of class msdk::Message:
         Message( int command = 0, DataCopy dataCopy = KEEP_STATIC, int dataLength = 0, void* dataBuffer = 0 ) - Constructor. The dataCopy option is explained above.
         Message( const MessagePayload& payload, int command = USER ) - Constructor from MessagePayload.
         void Clear() - Clears the content of the message instance.
         bool GetPayload( MessagePayload& payload ) const - Clears Re-initializes paylod from DataBuffer, i.e invokes payload.FromBuffer( DataLength, DataBuffer ).
         int Command - The message command. User commands must be higher than the value of msdk::Message::USER. There is one system command predefined msdk::Message::QUIT. The latter is used to attempt to stop a thread gracefully in Windows. See the explanation under Thread.
         bool IsDisposable - True if the buffer is disposable and thus will be released by the destructor; false otherwise - the buffer is owned by the calling thread.
         int DataLength - Number of bytes in the data buffer.
         char* DataBuffer - Pointer to the beginning of the data buffer.


                  MessagePayload

MessagePayload is a pure-abstract class (interface). It provides a standard way of serializing any class to and from a binary buffer. Public overridable methods of interface msdk::MessagePayload:
         virtual int ComputeBufferSize() const = 0 - Must return the number of bytes needed to store the implementing instance in a binary buffer.
         virtual bool ToBuffer( char* dataBuffer ) const = 0 - Must serialize the implementing instance into dataBuffer. ComputeBufferSize() has already been called and dataBuffer is already allocated.
         virtual bool FromBuffer( int dataLength, const char* dataBuffer ) = 0 - Must re-construct the implementing instance from dataBuffer. dataLength must be at least the required value and may exceed it (there may have been some extra bytes allocated).


                  BlockingSequence

Blocking sequence is a thread-support primitive that implements the thread message queue. Class msdk::BlockingSequence is more generic than a specific message queue in two ways:
The MSDK blocking sequence exceeds the Win32 thread message queue functionality by allowing multithreading at both ends of the queue. For instance, in Windows any thread can post a message to another thread but only the owner thread may pop the messages. Thus a Win32 message queue supports multithreading only at the pushing end.
Public methods of class msdk::BlockingSequence< class PAYLOAD >:
         bool IsEmpty() - True if the sequence is empty; false otherwise.
         bool Pop( PAYLOAD& payload ) - Loads the front payload into the provided reference and removes it from the sequence.
         bool Peek( PAYLOAD& payload ) - Loads the front payload into the provided reference without removing it from the sequence.
         bool PushBack( const PAYLOAD& payload ) - Puts a copy of the payload at the back of the sequence queue behavior.
         bool Push( const PAYLOAD& payload ) - Puts a copy of the payload at the front of the sequence stack behavior.


                  Thread

Thread is a well-known OS primitive. Historically threads are first introduced in VMS and later made popular in its spiritual successor Windows. Thus Windows has a longer history than UNIX of employing threads. The Win32 API and the Pthread library follow different paradigms, which makes developing cross-platform code tedious. The MSDK Thread primitive exposes a common API that tries to unify the two paradigms.

Class msdk::Thread is the most essential class of the thread support in MSDK. Creating an instance of class msdk::Thread does not spawn a new OS thread. To do so, the Start() method must be explicitly invoked. Stopping a thread is slightly different in Windows and UNIX. Windows does not have a mechanism to stop a thread gracefully in the general case a thread may be terminated (brutally killed), or it may be posted a WM_QUIT message, in which case the thread must be parsing its own message queue for that to work. In UNIX the Pthread library maintains a cleanup stack for each thread, so that when it is canceled, the cleanup procedures a popped from the stack and executed. With regard to thread execution Windows outperforms UNIX by providing each thread with a built-in blocking message queue, while still supporting the notion of the worker thread.

The thread paradigm of MSDK is closer to Windows in a sense that each thread has the choice of executing a given task (worker thread) or parse messages from its own blocking message queue. On top of that MSDK provides the Pthread benefits of maintaining a startup- and shutdown event handlers.

Public methods of class msdk::Thread:
         Thread( void* data = 0 ) - Constructor. Initializes a new instance with the provided data buffer. Does not spawn a new OS thread.
         bool Start() - Spawns a new OS thread. This will cause the following overridable methods to be invoked on behalf of the new thread in the given order: Startup(), Run(), Shutdown(). Returns true if a new OS thread was spawned, false otherwise.
         bool Stop() - Attempts to stop a thread gracefully. See considerations above. This may not be possible for worker threads in Windows. If the thread responds to this event, the Shutdown() overridable method will be invoked on its behalf. Returns true if the lower-level call succeeded. It does not mean the thread was really stopped.
         bool Terminate() - Brutally kills the thread. No overridable method is invoked. This may leave unreleased resources. This method should be used as a last resort. Returns true if the lower-level call succeeded. If the thread is still running, there isnt much that could be done.
         bool PostMessage( const Message& message ) - Posts a message to this Thread instance. Returns true if the message was posted successfully. It doesnt guarantee the thread will process it.
         bool WaitUntilFinished() - Blocks the calling thread until this Thread instance stops. Returns true on success, false otherwise.
         void Sleep( unsigned int seconds, unsigned int milliseconds = 0 ) - in UNIX it is not known whether the system sleep() function is cancelable. This method is guaranteed to be cancelable. Also, this method provides the convenience to use smaller numbers with high resolution. The time to sleep is: seconds + milliseconds. Milliseconds must be less than 1000.
         ThreadID GetThreadID() - Returns the thread ID that could be used as a parameter to lower-level function calls.
         bool IsThreadRunning() - Returns true when the thread is known to be running. It may be blocked on shared resources though.
         bool IsThreadIdle() - Returns true when the thread is waiting for new messages.

Public overridable methods of class msdk::Thread:
         virtual bool Init( void* initData = 0 ) - May be invoked before Start() to trigger thread initialization. The method may be overridden by Thread successors to customize their own initialization. Returns true if initialization passed, false otherwise.

Protected overridable methods of class msdk::Thread:
         virtual void Startup() - This is the first method invoked on behalf of the OS thread. The default implementation is dummy.
         virtual void Shutdown() - This is the last method invoked on behalf of the OS thread. The default implementation is dummy.
         virtual void Run() - This is the main thread procedure. It is invoked on behalf of the OS thread right after Startup(). The default implementation consists of a message pump that quits execution when msdk::Message::QUIT command is sent. Otherwise it invokes ProcessMessage() for every other message.
         virtual void ProcessMessage( const Message& /* message */ ) - Invoked by Run() for every new message in the threads message queue.

In conclusion, to implement a worker thread override Run() with the code of your need. To implement a message processing thread, override ProcessMessage(). Startup() and Shutdown() are useful when there are resources to be initialized/released.


                  Buffer

Buffer is a very simple class that given a integer, allocates space on the heap to accomodate a character string of that length. A Buffer instance is automatically cast to ( char* ) and ( const char* ). This functionality is supported by class std::string but it showed memory leaks under Linux.

Public methods of class msdk::Buffer:
         Buffer( size_t length = 0 ) - Constructor.
         Buffer( const Buffer& buff ) - Copy constructor.
         void Free() - Releases any allocated memory and clears the buffer.
         bool Alloc( size_t length ) - Re-allocates memory. If tere is already some memory allocated, it is released first. Allocates length + 1 bytes to ensure the trailing '\0' could be accommodated.
         size_t Length() const - Returns the current length of the buffer excluding the byte for the trailing '\0'.
         operator char*() - Implicit cast to ( char* ).
         operator const char*() const - Implicit cast to ( const char* ).


                  Utilities

The utilities module is a set of public common-use types and functions:

Types:
         ProcessID - Process ID compatible with the type used by the platform API - DWORD in Windows, pud_t in UNIX.
         Time - Currently this is a synonim of - tm which is supported in both Windows and UNIX.

Functions:
         inline ProcessID CurrentProcessID() - Returns the current process ID.
         inline ThreadID CurrentThreadID() - Returns the current thread ID. Type ThreadID is defined along with class msdk::Thread.
         inline Time CurrentTime() - Returns the current time.
         inline int stroptcmp( const char* s1, const char* s2, bool caseSensitive ) - Compares two string with an option of case-sensitivity. The result is the same as the result of function strcmp(). Function strcasecmp() is defined in Windows as a mapping to _stricmp().
         inline char* strnset( char* s, char c, size_t n, bool force = false ) - Sets up to n chars to ch at position s. Allows using force to go beyon the trailing '\0'.
         inline char* strdupcat( const char* s1, const char* s2 = 0 ) - Creates a copy of the concatenation of the two strings. The returned copy must be freed by the caller.
         inline int strchrchr( char* str, char x, char y, int n = -1 ) - Replaces up to n occurrances of a char within a buffer with another char. The buffer must be writable.
         inline int mkdirhier( const char* path, int mode = 0775 ) - Makes sure the entire path exists. May create more than one level of directories. The path may have a trailing '/'.


         Process Support

The process support entities are defined in namespace msdk::process.

                  Log

Log is a Thread-derivate that records messages in text files. The reason why Log is a separate thread is to prevent the worker threads from wasting time accessing the file system. Second, the Log thread may impersonate an account that has access to places of the file system where worker threads do not have access. Log is a template class. Its parameter is a MessagePayload-derivate.

Class msdk::process::Log has one public enumerator - LogMessageCommand for message commands recognized by the default implementation of class Log: Public methods of class msdk::process::Log:
         Log( int cutOffLevel = LOG_LEVEL_DEBUG ) - Constructor. The cutOffLevel is a simple way to build instrumented and release versions of the same system. Each LOG_MESSAGE request has a level. Messages with levels under the cutOffLevel of the Log instance are not logged. The possible log levels are:          bool Write( const MESSAGE_PAYLOAD& payload, int command = LOG_MESSAGE ) - Wraps up payload into a Message and posts it to the Log. Returns before the message is processed.

Protected overridable methods of class msdk::process::Log:
         virtual bool GetLogFileDir( const MESSAGE_PAYLOAD& /* payload */, Buffer& dir ) - Must return the (full) path to the directory where the log file will be placed. The Log will make sure that directory exists. The payload is used in case on Log instance supports multiple log files. The payload should give enough information which log file is the subject. dir is already allocated.
         virtual bool GetLogFilePath( const MESSAGE_PAYLOAD& /* payload */, Buffer& path ) - Must return the (full) path to the log file. path is already allocated.
         void ProcessMessage( const Message& message ) - Overrides msdk::Thread.


                  Config

Class Config manipulates text configuration files. A file contains configuration rows and comments. A row contains columns. Different rows may have different number of columns. Columns are added dynamically when needed. The default column separator is '|' but a different character could be specified. The default comment character is '#' and comments out the line to its end. It may also be overriden.

Public methods of class msdk::process::Config:
         Config( const char* filePath, char columnChar = ConfigColumnChar, char commentChar = ConfigCommentChar ) - Constructor.
         bool DeleteRow( const char* id, bool caseSensitive = true ) - Deletes a row by row ID.
         bool UpdateRow( const char* row, bool caseSensitive = true ) - Updates a row.
         bool SetRow( const char* id, const char* row, bool caseSensitive = true ) - A generic methof that implements both modification and deletion of a row. If row is NULL, the row is deleted. Otherwise row provides the new value for the row.
         bool AddRow( const char* row ) - Adds a new row.
         bool GenerateRowID( Buffer& id ) - Generates a new textual row ID. id must be already allocated.
         bool GetRow( Buffer& row, const char* id, bool caseSensitive = true ) - Finds a row by row ID. The row IDs generated by this implementation contain digits only. However MSDK allows config files and row IDs to be modified manually.
         bool FilterRow( Buffer& row, int n = 0, const ConfigConstraint filter[] = 0, bool caseSensitive = true ) - Finds the first row that satisfies the constraint. ConfigConstraint is a struct that has column index (Column) and textual value (Value). filter is an AND of all the given constraints.
         bool FilterRowSeq( long& pos, Buffer& row, int n = 0, const ConfigConstraint filter[] = 0, bool caseSensitive = true ) - Sequentially finds all rows that satisfy the filter. This method shuld not be used in conjunction with methods that modify the content of the config file because that may invalidate pos.
         bool MatchFilter( const char* row, int n, const ConfigConstraint filter[], bool caseSensitive = true ) - Returns true if the row satisfies the given filter and false otherwise.
         bool GetRowID( const char* row, Buffer& id ) - Extracts the rows ID (column 0) of the given row into an already allocated Buffer.
         bool GetCol( const char* row, int i, Buffer& col ) - Extracts the value of column i of the given row into an already allocated Buffer.
         bool SetCol( Buffer& row, int i, const char* col ) - Sets the value of column i of the given row.
         bool FindCol( const char* row, int i, const char*& start, const char*& stop, size_t& missing ) - This is a lower-level method for extracting a column from a row. If the column is found: start points to the first char of the column, stop points right behind the last char of the column and the method returns true. If the column does not exist: start and stop are undefined, missing returns the number of columns that must be added before the desired one, and the method returns false.


                  Service

Class Service provides a skeleton for an NT service under Windows, and a daemon under UNIX. A Thread-derivate class must be defined to represent the body of the service. An instance of that thread is created, started, and stopped by the service stub. A Service instance should not be created directly. Instead a macro should be used - MSDK_SERVICE_MAIN( ServiceThreadClass ) where ServiceThreadClass is that thread-derivate that implements the body of the service. That macro generates main()/WinMain(). Advanced MSDK users may choose not to use the macro and write their own main()/WinMain() instead.

Public methods of class msdk::process::Service:
         Service( Thread& thread, const char* serviceName = "Anonymous MSDK Service" ) - Constructor.
         void Main( bool runAsService = true ) - Main entry point. The parameter runAsService is irrelevant in UNIX since processes are always on their own. In Windows though, this parameter tells the service whether it should be submitted to the SCM (true) or whether it should run independently as a normal process (false).
         void Exit() - Stops the service body thread and exits from the process.


         Multithreading Applications

                  Single-Writer-Multiple-Readers

Single-WriterMultiple-Readers is a typical scenario in a multithreading environment some threads may perform their actions while sharing the resource with other threads (readers), and some other threads require exclusive access to perform their action (writers). Class msdk::ReadWrite is an elegant solution based on the MSDK semi-mutex primitive.

Public methods of class msdk::ReadWrite:
         bool SafeRead( void* data ) - Acquires a shared lock, invokes the overridable Read(), and releases the lock.
         bool SafeWrite( void* data ) - Acquires an exclusive lock, invokes the overridable Write(), and releases the lock.

Overridable methods of class msdk::ReadWrite:
         virtual bool Read( void* /* data */ ) - To be overridden with the custom read operation. The default implementation is dummy.
         virtual bool Write( void* /* data */ ) - To be overridden with the custom write operation. The default implementation is dummy.


                  Thread Pool

Thread pool is another typical scenario in a multithreading environment when scalability in processing incoming requests is required. The thread pool dispatches each incoming request to an available thread. (MSDK also provides another way to implement this scenario without using a ThreadPool instance. See the samples bellow.) Class msdk::ThreadPool is a template that receives as a parameter a class, PROCESSORTHREAD, that derives from msdk::Thread. That class must override the ProcessMessage() method. That is where the actual request processing is done.

Public methods of class msdk::ThreadPool< class PROCESSORTHREAD >:
         bool Start( int threadCount = 10, bool allMustStart = false ) Attempts to spawn the given number of threads. Returns true if it was required for all the threads to start and they did, or at leas one thread started and it wasnt required for all the threads to start, and false otherwise.
         int GetRunningThreadCount() - Returns the number of successfully started threads.
         bool Stop() - Gracefully stops all threads and waits for them to finish.
         bool PostRequest( const Message& message ) - Dispatches an incoming request. This will trigger the ProcessMessage() overridable method of one PROCESSORTHREAD instance.

Protected overridable methods of class msdk::ThreadPool< class PROCESSORTHREAD >:
         virtual bool InitThread( int threadIndex, void* initData = 0 ) Invoked within the loop of creating and starting up the threads. There is exactly one invokation per thread. The thread index starts from 0. The default implementation redirects the call to Thread::Init() and propagates the result. May be overridden by ThreadPool successors to customize the initialization of their own threads.


         Samples

Each sample consists of one .cpp file. To build the samples, navigate to the samples subdirectory and execute the following command:
WIN32 nmake f makefile-win
UNIX  make f makefile-unix


                  readwrite

This sample demonstrates how to implement a single-writer-multiple-readers scenario using class msdk::ReadWrite. The executable outputs messages when an operation starts/ends. The "vvv" notation means "start", and "^^^" means "end". For clarity write operation messages are indented to right. The number in each message represents the ID of the thread executing the operation. What you should see is that write operations are never nested while read operation may be.

MSDK classes directly utilized in this sample: ReadWrite, Thread.


                  async-threadpool

This sample demonstrates how to implement an asynchronous request processing scenario using class msdk::ThreadPool. The executable outputs messages when a request is being processed. Each message contains the sender thread ID, the ordinal request number for that sender, and the processor thread ID. The former two numbers are included in the request. What you should see is that messages originate from all senders and are processed by all processors.

MSDK classes directly utilized in this sample: ThreadPool, Thread, Message.


                  async-bqueue

This sample also demonstrates how to implement an asynchronous request processing scenario but this time without using class msdk::ThreadPool. Instead, it uses class msdk::BlockingSequence. The executable produces the same output as async-threadpool. Watch for the same things.

MSDK classes directly utilized in this sample: BlockingSequence, Thread, Message.


                  log

Shows how to usee the default Config implementation and log messages to the console.

MSDK classes directly utilized in this sample: Log, LogMessagePayload.


                  config

Shows how to use the Config class at its three levels: I/O-, Row-, and File.

MSDK classes directly utilized in this sample: Config, ConfigRow, ConfigIO, Buffer.


                  service

Shows how to implement a platform-independednt service. In Windows the service must be registered first, e.g. with the INSTSRV tool. The service logs a message at startup, shutdown, and every 2 seconds while running.

MSDK classes directly utilized in this sample: Thread, Log, LogMessagePayload.




Copyright 2004-2006, Zlatko Michailov