爱东东

VS.NET,IT,个人,个人网站 爱东东 http://www.idongdong.net

 

ZThreads讲解

ZThreads - Porting Guide


Introduction
Layout
What Does It Take?
    
  -  FastLock Concept
  -  Monitor Concept
  -  ThreadOps Concept
  -  TSS Concept
    
  -  FastRecursiveLock Concept (optional)
  -  TimeStrategy Concept (optional)


 Introduction

The purpose of this guide is to explain exactly what it takes to add support for other platforms to ZThreads. The 2.2.0 release of the library was completely reorganized and redocumented to help ease this process. Porting to new systems is very easy. Hopefully, this guide will help people intrested in doing this quickly. I hope to gain support for platforms I do not personally have access to, such as BeOS, MacOS, etc.

Please don't hesitate to contact me with any questions you have about adding new support to ZThreads.





Layout

This is a general description of the layout of the code. The intention here is to let you know where to look for things. I'm providing a enough information here to get you started adding a new implementation, but I'm assuming your somewhat familiar with compiling and linking on your platform.

The source code has been restructured to ease both compliation and to reduce the number of dependancies between files. The advantage to this is that it eases maintence, it simplifies the building process and it simplifies adding new implementations to the library.

All platform specific code resides in a subdirectory of src. For example, win32 houses the Win32 code, and so on.

incluce/zthread
src/
posix/
win32/
win9x/
vanilla/

The configuration of the library is controled through header files. Specifically, zthread/Config.h and src/config.h (generated if you use autoconf to configure the library). I would recommend using autoconf if possible, however, if your platform isn't UNIX-like, then you may have trouble doing so. For those cases, all the same parameters autoconf detects can be adjusted manually by editing the zthread/Config.h file. The zthread/Config.h file is currently arranged to to try an do the best job it can guessing what implementation is best for your system.

To compile ZThreads, simply build all the .cxx files in the src directory only, into a library. These files will automatically #include the correct files from the correct subdirectories (based on your configuration)

In order to add new implementations, simply create a new subdirectory and place your new code there. This code should be comprised of at least the four required primatives described in this document.

incluce/zthread
src/
posix/
win32/
win9x/
vanilla/
new-platform/

In the src directory, you'll find files that are named after the primatives you'll be implementing (Monitor.cxx, Monitor.h, FastLock.h, etc.) These files simply contain a series of #ifdef's that select the correct files from the correct subdirectories. After adding a few lines to these files, you'll be ready to compile support for your new platform.





What Does It Take?

What does it take to implement this type of library? Well, the initial implementation was a bit different from what you'll find today. I've boiled things down to try and simplify the internals quite a bit since the first implementation. The library is implemented on top of several important synchronization primatives These primatives are relatively simple and can be implemented correctly on any platform, no matter what the native thread model is. This task is not as daunting as you might think at first. The primatives are very basic, all of the more advanced features provided by the library are handled at a higher level.

Classes need to be provided for these these things, but there is no interface they must implement that dictates the required methods and effects. Because of this, I will describe the requirements for these primatives in terms of Concepts. The pre-conditions and post-conditions desribe the excepected use in more detail, any error checking for these conditions should be done in terms of assertions for debug mode only.

There is a set of tests that is included with the library that you may find useful when testing your implementation of these primatives. These tests are not complete - but they are a helpful and good start.


 FastLock Concept

The FastLock is the easier of the two synchronization primatives to implement. A FastLock can simply be implemented using a spin lock (though its best to use a more rocust mechanism), or by using whatever locking primative your platform supports. This object encapsulates acquire (lock), tryAcquire (try lock) and release (unlock) operations.

The library includes several strategies for implementing this primative on MacOs, POSIX and Win32 systems which may be helpful in finding an approach that will work for your system

Expression Requirement
FastLock l; Effect: Construct a new FastLock.
Detail: The Monitor is NonCopyable
(&l)->~FastLock(); Effect: Destroy a FastLock.
Pre Condition: No thread should not have acquire()d the lock when this object is destroyed.
l.acquire(); Effect: Acquire an exclusive lock.
Detail: Blocks the calling thread until an exclusive lock can be obtained. This may block indefinently.
Return: void
Pre Condition: The calling thread should not have already acquire()d the lock.
Post Condition: No other thread may acquire the native lock until the caller release()es it.
l.tryAcquire(); Effect: Attempt to acquire an exclusive lock.
Detail: May not block the calling thread indefinently. If an exclusive lock can be obtained, without blocking, then that exclusive lock is obtained on the the native object and true is returned immediately. Otherwise false is returned.
Return: bool
Pre Condition: The calling thread should not have already acquire()d the lock.
Post Condition: No other thread may acquire the native lock until the caller release()es it, only if this function returned true.
l.release(); Effect: Attempt to release an exclusive lock.
Detail: May not block the calling thread indefinently. An exclusive lock on teh native object is released, allowing it to be acquired by another thread.
Return: void
Pre Condition: The calling thread should have already acquire()d the lock.

Some test cases are provided that will give your mutex a workout. Its recommended that you run those to be sure the new implementation works correctly.


 





Monitor Concept

The Monitor is the hardest synchronization primative to implement. Its responsible for maintaining a somewhat complex state, as well as blocking and releasing threads. Details for maintaing the State are encapsulated in the Status class, the Monitor concept must simply apply the right transitions to an instance of that class. Each thread owns and waits on only one monitor. The outline below specifies whch methods may potentially be called by multiple threads. Access to the status of the Monitor must be serialized within each of the methods described below. No changes should be made to the Status object when adding a new implementation..

The library includes implementations of this primative for both Win32 and on POSIX systems. Looking at these implementations is strongyl recommended when implementating a new one.

Expression Requirement
Monitor m; Effect: Construct a new Monitor.
Detail: The Monitor must extend the Status class.
Detail: The Monitor is NonCopyable
(&m)->~Monitor(); Effect: Destroy a Monitor.
Pre Condition: No thread should be wait()ing on this monitor.
l.acquire(); Effect: Acquire an exclusive lock.
Detail: Blocks the calling thread until an exclusive lock can be obtained. This may block indefinently.
Return: void
Post Condition: No other thread may acquire the native lock until the caller release()es it.
Used by: Any thread
l.tryAcquire(); Effect: Attempt to acquire an exclusive lock.
Detail: May not block the calling thread indefinently. If an exclusive lock can be obtained, without blocking, then that exclusive lock is obtained on the the native object and true is returned immediately. Otherwise false is returned.
Return: bool
Post Condition: No other thread may acquire the native lock until the caller release()es it, only if this function returned true.
Used by: Any thread
l.release(); Effect: Attempt to release an exclusive lock.
Detail: May not block the calling thread indefinently. An exclusive lock on teh native object is released, allowing it to be acquired by another thread.
Return: void
Pre Condition: The calling thread should have already acquire()d the lock.
Post Condition: No other thread may acquire the native lock until the caller calls release() for each time it called acquire().
Used by: Any thread
l.wait(); Effect: Atomically release() the exclusive lock and block the current thread until ANYTHING is pending()
Detail: This may block indefinently.
Return: Status::STATE - the next() state
Pre Condition: The external lock must be held when this function is called.
Post Condition: The external lock must be held when this function is returns.
Post Condition: Spurrious wakeups are not acceptable, this function must return only when pending(ANYTHING) returns a valid STATE.
Used by: OWNER ONLY
l.wait(unsigned long ms); Effect: Atomically release() the exclusive lock and block the current thread until ANYTHING is pending(), for at most ms milliseconds.
Detail: This may block indefinently only ifms is 0.
Return: Status::STATE - the next() state
Pre Condition: The external lock must be held when this function is called.
Post Condition: The external lock must be held when this function is returns.
Post Condition: Spurrious wakeups are not acceptable, this function must return only when pending(ANYTHING) returns a valid STATE.
Used by: OWNER ONLY
l.cancel(); Effect: Atomically update the canceled status.
Detail: This may not block indefinently. If the CANCELED status is not set, then push(CANCELED).If the INTERRUPTED status not pending then push(INTERRUPTED) and signal the wait()er (if it exists).
Return: bool - true if the status was updated.
Used by: Any thread.
l.interrupt(); Effect: Atomically update the interrupted status.
Detail: This may not block indefinently. If the INTERRUPTED status is not pending(), then push(INTERRUPTED) and signal the wait()er (if it exists).
Return: bool - true if the status was updated.
Used by: Any thread.
l.notify(); Effect: Atomically update the signaled status.
Detail: This may not block indefinently. If the INTERRUPTED state is not pending(), then push(SIGNALED) and signal the wait()er (if it exists).
Return: bool - true if the status was updated.
Used by: Any thread.
l.isInterrupted(); Effect: Atomically test, and possibly update, the interrupted status.
Detail: This may not block indefinently.
Return: bool - result of pending(INTERRUPTED).
Post Condition: If called from the OWNER thread, the INTERRUPTED state is cleared. Used by: OWNER thread.
l.isCanceled(); Effect: Atomically test, the canceled status.
Detail: This may not block indefinently.
Return: bool - result of check(CANCELED)
Post Condition: If called from the OWNER thread, the INTERRUPTED state is cleared. Used by: Any thread.

That's it. All you need to do now is to update the configuration and run the test cases to make sure you've implemented this primative correctly.





ThreadOps Concept

The ThreadOps primative is responsible for providing access to only the most basic native thread operations.

Expression Requirement
ThreadOps t; Effect: Construct a new ThreadOps.
Detail: This ThreadOps is not associated with any particular thread.
(&t)->~ThreadOps(); Effect: Destroy a TSS.
Post-Condition: join() should be called prior to the destructor if this object was used to spawn a native thread.
ThreadOps::INVALID; Effect: Provide access to a staitc const ThreadOps that has been created with the default constructor.
Post-Condition: Can't be used for anything other than comparison.
(&t)->==(t); Effect: Provide const comparison (==) operator that compares a ThreadOps to a const ThreadOps&.
Return: true if the two objects refer to the same native thread.
ThreadOps::self(); Effect: Create a ThreadOps that is associated with the currently executing native thread.
Post-Condition: Can't be used for anything other than comparison.
ThreadOps::activate(t); Effect: Activate a ThreadOps, associating it with the currently executing native thread.
Pre-Condition: A ThreadOps can't be activated twice.
ThreadOps::isCurrent(t); Effect: Compare a ThreadOps with the currently executing native thread.
Return: true if the ThreadOps was activated from the currently executing native thread.
ThreadOps::join(t); Effect: Join the native thread associated with this ThreadOps.
Return: true if successful, otherwise false.
Pre-Condition: The ThreadOps must have been used to spawn a native thread.
Pre-Condition: The ThreadOps must not have been join()ed already.
ThreadOps::yield(); Effect: yield the current threads timeslice, allowing the scheduler to switch to another thread sooner.
Priority p; ThreadOps::setPriority(t, p); Effect: Update the effective priority of the native thread represented by the ThreadOps.
Return: true if successful, otherwise false.
Priority p; ThreadOps::getPriority(t, p); Effect: Get the effective priority of the native thread represented by the ThreadOps.
Return: true if successful, otherwise false.
Runnable* r; t.spawn(r); Effect: Execute the runnable task from the context of the native thread associated with the ThreadOps.
Return: true if successful, otherwise false.
Pre-Condition: The ThreadOps must not been used to spawn a native thread already.
Pre-Condition: The ThreadOps must not have been join()ed already.


 TSS Concept

The TSS primative is a template class that provides simple access to an operating systems thread-specific-storage. ZThreads provides a rich set of classes that greatly enhance the TSS provided to an application; fortuneately, none of that is implemented in the TSS primaitve - so its really very simple to implement. I'm not familair with any platforms that do not support TSS, however it should be possible to emulate if you are porting to such a platform.

Expression Requirement
TSS t; Effect: Construct a new TSS.
(&t)->~TSS(); Effect: Destroy a TSS.
t.set(T*); Effect: Store a pointer value of type T in the native TSS.
Return: A pointer value of type T that was previously stored in the native TSS.
t.get(T*); Effect: Retrieve a pointer value of type T from the native TSS.
Return: void

That is all that is required. It can be used simply,

TSS<int> tss;
                                                                                tss.set(new int(9));
                                                                                cout << *tss.get() << endl;
                                                                                Output: 9
                                                                                

 FastRecursiveLock Concept (optional)

The FastRecursiveLock is similar to the FastLock. The difference is that it may be acquire()d repeatedly by the same thread. It must be release()d as many times as it was acquired. Implementing this is optional, ZThreads provides a vanilla implementation based on the required FastLock.

The library includes several strategies for implementing this primative on Win32 and on POSIX systems which may be helpful in finding an approach that will work for your system

Expression Requirement
FastRecursiveLock l; Effect: Construct a new FastRecursiveLock.
Detail: The Monitor is NonCopyable
(&l)->~FastRecursiveLock(); Effect: Destroy a FastRecursiveLock.
Pre Condition: No thread should not have acquire()d the lock when this object is destroyed.
l.acquire(); Effect: Acquire an exclusive lock.
Detail: Blocks the calling thread until an exclusive lock can be obtained. This may block indefinently.
Return: void
Post Condition: No other thread may acquire the native lock until the caller release()es it.
l.tryAcquire(); Effect: Attempt to acquire an exclusive lock.
Detail: May not block the calling thread indefinently. If an exclusive lock can be obtained, without blocking, then that exclusive lock is obtained on the the native object and true is returned immediately. Otherwise false is returned.
Return: bool
Post Condition: No other thread may acquire the native lock until the caller release()es it, only if this function returned true.
l.release(); Effect: Attempt to release an exclusive lock.
Detail: May not block the calling thread indefinently. An exclusive lock on teh native object is released, allowing it to be acquired by another thread.
Return: void
Pre Condition: The calling thread should have already acquire()d the lock.
Post Condition: No other thread may acquire the native lock until the caller calls release() for each time it called acquire().

Some test cases are provided that will give your mutex a workout. Its recommended that you run those to be sure the new implementation works correctly.


 TimeStrategy Concept (optional)

The TimeStrategy concept is used to provide access to a timer with millisecond resolution. Most systems are equiped with a flavor of ftime() or gettimeofday() and there are TimeStrategy implementations included that use those functions. However, some people may want to use a more precise timer, or may be intrested in adding nanosecond resolution to the library. For those people, the TimerOps concept is described below.

Expression Requirement
TimeStrategy t; Effect: Construct a new TimeStrategy.
Detail: The TimeStrategy should represent the current time.
(&l)->~TimeStrategy(); Effect: Destroy a TimeStrategy.
t.seconds(); Effect: Get the seconds value.
Return: unsigned long
t.milliseconds(); Effect: Get the milliseconds value.
Return: unsigned long
unsigned long s; t.seconds(s); Effect: Set the seconds value.
Return: unsigned long The previous seconds value.
unsigned long ms; t.milliseconds(ms); Effect: Set the milliseconds value.
Return: unsigned long The previous milliseconds value.


 Copyright © 2000 - 2002,  Eric Crahen <crahen at cs dot buffalo dot edu> - All rights reserved.
Permission to use, copy, modify, distribute and sell this documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Eric Crahen makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.

posted on 2007-11-06 17:33  爱东东  阅读(1101)  评论(0编辑  收藏  举报

导航