home *** CD-ROM | disk | FTP | other *** search
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- OS/2 THREADS COOKBOOK _____________________
-
-
-
-
-
- Version 1.2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Stephen Best
- P.O. Box 3097
- Manuka A.C.T. 2603
- Australia
-
- Phone: 61-6-281-2147
- FidoNet: 3:620/243.4
- CompuServe: 100033,340
-
-
-
-
-
-
-
-
-
-
-
- Copyright (c) 1991, 1992 Stephen Best
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- This document is an attempt to collect together and share a
- number of my observations and ideas about programming for
- OS/2 Presentation Manager using multiple threads that have
- evolved over time and been gleaned (gratefully) from other
- explorers in this area. A thorough understanding of the use
- of threads is essential for construction of all but the most
- trivial Presentation Manager programs and it is hoped that
- the ideas contained herein with be of aid to programmers
- beginning to tap into the exciting possibilities that the
- use of multiple threads introduce.
-
-
- If you would like the full C source for the examples
- discussed herein, please contact me via FidoNet/CompuServe
- or at the address given with your Mastercard/Visa
- particulars. The cost is $A45 (approx. $US34) with free
- transfer via CompuServe. An additional $A10 will be charged
- for postal delivery if required (3.5 inch media only).
- Payment entitles the licensee to use the source from the
- examples in any programs of their own.
-
-
- Also, if you have any comments at all regarding the material
- contained herein, including errors and omissions, I would be
- more than happy to hear of them.
-
-
-
- Stephen Best
-
- 28 February, 1992
-
-
-
-
-
-
-
-
-
-
-
- Contents
- ________
-
-
-
-
-
- Introduction 3
-
- What is a thread? 4
-
- Message queues 5
-
- Performance and restrictions 7
-
- Managing threads 8
-
- DosCreateThread vs. _beginthread 10
-
- Window data 11
-
- Example 1 11
-
- Example 2 13
-
- Other possibilities 14
-
- Conclusion 15
-
- References 16
-
-
-
- OS/2 Threads Cookbook page 3
-
-
-
- Introduction ____________
-
- OS/2 as a single user system has the potential to
- substantially change the user's perception as to how a
- personal computer should work. Programs using multiple
- threads can not only increase execution performance (both
- perceived and actual) but also change the emphasis in user-
- application interaction to one where the user has more
- control and flexibility and where the application itself
- takes on a passive role. The program should always be
- receptive to interaction with the user even if this is just
- the capability for that user to change his/her mind after
- initiating a lengthy activity.
-
- Users that repeatedly tell you that "they don't need to
- multitask" will have great difficulty in reverting to single
- threaded software after having had the luxury of using a
- well designed and responsive multi-threaded application.
- Thus anyone wishing to compete in the market may have a hard
- time selling their product in an increasingly aware public
- arena. It is also hoped that all programmers will want to
- wring the maximum result from an environment for their
- efforts, and I think multiple threads have the potential for
- good returns in this area.
-
- It is also true, though not universally appreciated, that
- programming to the multi-threaded model has significant
- impact on the overall program design, and it is important to
- have this in mind up front to avoid major restructuring of
- the program at a later stage.
-
-
- This document is aimed at the OS/2 programmer wishing to tap
- into the power that programming with multiple threads
- provides. As such, I will attempt to cover all the essential
- issues related to threads, a guide to where and when I think
- threads are applicable and some substantial coding examples
- that I think demonstrate this. These examples are in C and
- are for OS/2 2.x, though conversion to other languages
- and/or OS/2 1.x should not be too difficult once the
- concepts are understood.
-
- All code has been tested with IBM OS/2 2.0 pre-release level
- 6.177 on an IBM PS/2 Model 80. The IBM C Set/2 compiler,
- linker and 6.177 toolkit headers were used.
-
-
- It is my belief that practically ALL programs for OS/2
- Presentation Manager will benefit from using multiple
- threads in their design, and indeed have a responsibility to
- do so given the message switching architecture of PM.
- Comments (especially those from sources with a vested
- interest in promoting second rate software products) that
-
-
-
- OS/2 Threads Cookbook page 4
-
-
- there is only a minimal requirement for multi-threaded
- program design should be considered in the light of the
- immediate and obvious benefits that their proper use can
- achieve.
-
- Polemics over, let's learn about OS/2 threads.
-
-
- What is a thread? _________________
-
- The thread is the basic level of execution under OS/2 and is
- roughly equivalent to the task of other systems. A program
- (or process) has a single thread at the beginning of its
- execution and can optionally split the activity of that
- program over a number of threads. Each thread of execution
- will be time-sliced on the processor (CPU) of the computer
- together with other threads of that application, and those
- of other applications active concurrently. A priority
- mechanism exists to ensure that the thread with the highest
- priority is always active, with control passing to other
- threads of a lower priority when the higher 'blocks' or is
- waiting on an event. On top of this OS/2 has a sophisticated
- scheduler to dynamically alter thread priority to achieve
- responsive overall performance or multitasking within the
- system.
-
- Note that splitting a single processor intensive task over a
- number of threads does not in itself achieve anything as the
- processor itself is a finite resource which cannot be driven
- beyond its capacity. Indeed the housekeeping in alternately
- dispatching threads may slow down execution in this case.
- (It may be worthwhile though to keep in mind that a future
- version of OS/2 may well support multiple physical
- processors, and the requirement for dividing compute bound
- tasks will change in this case).
-
- The criteria for dividing a process into threads as
- discussed herein is aimed at isolating the activity of a
- program by either priority, functional units or access to a
- resource.
-
- Consider an application which presents the user with a
- number of child windows or 'views', of which only one (the
- active window) can receive the keyboard focus at a time. It
- would in this case make sense to give the active/focus
- window a higher priority than the others, if concurrent
- activity in other windows is likely to impede the
- responsiveness of the one with which the user is interacting
- at that time. This can be achieved quite easily by assigning
- each window its own 'worker' thread and setting the priority
- of the active/focus window thread higher than that of its
- siblings. In this case the thread for the active window will
- receive the processor resource that it requires without
-
-
-
- OS/2 Threads Cookbook page 5
-
-
- interference from the other windows, aiding in the perceived
- responsiveness of the application.
-
- Actual overall efficiency can be achieved by overlapping
- processor intensive tasks with those for input/output eg.
- disk I/O. OS/2, as a true pre-emptive multitasking system,
- can balance the priorities between processes to maximize
- throughput but it is the application's responsibility to
- separate within itself lengthy I/O tasks from processor
- intensive ones, and especially those likely to interfere
- with servicing of the system message queue (more on this
- important area later). For example, if a user initiates a
- lengthy file open/save operation or printing activity it
- should be possible to interrupt this activity if the user
- changes his/her mind, or still interact with other facets of
- the application in parallel with the I/O activity. Failure
- to split this activity off from the primary thread can even
- inhibit the user's ability to switch to another unrelated
- application on the desktop. In this case, it may be
- advantageous to spawn a thread specifically for servicing
- the disk or printer asynchronously. The main thread could
- then off-load such tasks and 'queue' them to a background
- thread, and get on business of interacting with the user.
- Note that in this case it makes no sense to have a number of
- threads for a single resource (like a printer) as no
- efficiency is gained.
-
- It may be helpful to think of a one for one correspondence
- between threads and 'resources' (be they windows or the disk
- or a printer), with a 'master' thread interacting with the
- user (and hence the system message queue). It is this
- concept of resource based threads that will be expounded
- upon in the following.
-
-
- Message queues ______________
-
- Presentation Manager (among other GUI systems) has a message
- switching architecture to facilitate the routing of messages
- of different types among the 'windows' that make up the
- presentation layer for OS/2. An application can receive
- messages from the system eg. when a user attempts to re-size
- a window, or can send messages to itself or other windows in
- the system. Messages can either be SENT (explicitly with
- WinSendMsg or implicitly with a large number of other API
- calls eg. WinSetWindowText) or POSTed (with WinPostMsg).
- Sent messages (and those API calls that result in sent
- messages) will be turned into direct calls to the window
- procedure for the window specified in the send. Posted
- messages on the other hand will be queued in the
- application's message queue for deferred execution.
-
- The application message queue is created by the application
- itself with WinCreateMsgQueue and it is the act of doing so
-
-
-
- OS/2 Threads Cookbook page 6
-
-
- that distinguishes that application as a Presentation
- Manager one (as opposed to a character mode application
- executing in its own session). An application may create as
- many message queues as desired provided that only one
- message queue exists for each thread. Message queues other
- than the primary one are optional in multi-threaded
- applications and the following examples will attempt to
- demonstrate where multiple application message queues might
- be applicable.
-
- Messages queued on a message queue (by the system or the
- application itself) are un-queued with (generally) WinGetMsg
- in a message loop and then dispatched to the appropriate
- window procedure with WinDispatchMsg. This WinDispatchMsg
- can be thought of as turning the POSTed message into a SEND
- for immediate execution. In both cases, the window handle
- given specifies the appropriate window procedure for that
- message ... the association between window handle and
- procedure (for other than pre-registered classes) is made by
- the application with the combination of WinRegisterClass and
- WinCreate(Std)Window.
-
- The system message queue (of which there is only one for the
- whole Presentation Manager session) is provided to queue
- those 'messages' that will be subsequently distributed to
- the appropriate application message queue(s) at such time
- that the context of the message can be determined. The
- primary consideration here is user input (both keyboard and
- mouse actions) that may occur asynchronously to the
- application message flow. The 'problem' for PM programs is
- that the application processing of any message can itself
- change the destination for keyboard and mouse messages
- pending in the system message queue (eg. explicitly with
- calls WinSetFocus or WinSetCapture) and thus it is only when
- PM itself regains control from prior messages that it is
- possible to determine the appropriate application queue in
- which to place the keyboard or mouse message. In addition,
- the program is responsible for processing messages dealing
- with loss of focus and activation before other windows can
- be activated. The implication for a PM program is that it
- should always be available for processing user input events,
- and process all incoming messages quickly.
-
- The methodologies discussed in this document are aimed at
- off-loading the bulk of the processing requirement for the
- application from the 'input' message thread to other 'non-
- input' threads, making the application always receptive to
- user input, and thus increasing the responsiveness of the
- application and the system as a whole. It may be helpful to
- consider that serialization of keyboard and mouse messages
- in the system queue is not so much a 'problem' to be
- overcome with adding threads, but that the main 'input'
- thread of the application is just a vehicle for receiving
-
-
-
- OS/2 Threads Cookbook page 7
-
-
- input from the system and like all shared resources, to be
- treated accordingly.
-
-
- Performance and restrictions ____________________________
-
- Sent messages can be processed faster than posted messages
- because they never appear in the message queue of the
- application and thus avoid the message loop altogether. The
- throughput of inter thread posts will be slower still. This
- is not to say that posts should be avoided, but that it may
- be desirable to use sends rather than posts when an clear
- choice exists between the two. Sends also have the guarantee
- that any dynamic memory area addressed by the message
- parameter(s) will remain current for the life of the send,
- which is a benefit if more data than the eight bytes
- permitted with the two 32 bit message parameters themselves
- is required. As a bonus, the return code from the receiving
- window procedure method is available upon completion of the
- send. Sends (because they are translated into calls to the
- window procedure) will cause the window procedure(s) to be
- called recursively, and thus may place excessive demands on
- the program stack with high levels of recursion.
-
- Posts on the other hand, because of their asynchronous
- nature will be serialized in the message queue and processed
- when the application itself enters message loop processing.
- This means that any dynamic data addressed by message
- parameters when the post was issued may no longer be valid.
- This consideration requires a number of differing techniques
- to transfer more data than the message parameters themselves
- permit. Another important point to note about posts is that
- the message may not actually be posted should the message
- queue be full at the time of the post. The return code from
- WinPostMsg should thus be checked to see if the post was in
- fact accepted and implementing a delayed retry or some
- pacing algorithm to ensure the message is not lost. Despite
- the above, posts will play a big part in the interaction of
- and communication between threads and thus the techniques
- for achieving efficient and reliable use of them is
- presented herein.
-
- Another difference between sends and posts is the context in
- which it is valid to issue them. Posts can be issued without
- restriction between threads and will appear in the message
- queue of the thread with which the window addressed (by the
- window handle specified) was created. A variation on
- WinPostMsg is WinPostQueueMsg where the handle of the
- message queue itself is specified instead of the window
- handle. This permits an application to queue messages to
- another thread (assuming the receiving thread has created
- its own message queue) when no actual window procedure may
- exist for that thread. This variation will be explored in
- one of the following examples.
-
-
-
- OS/2 Threads Cookbook page 8
-
-
-
- Sends on the other hand can only be issued between threads
- each having a message queue, and for reasons following
- should be avoided for anything other than intra thread
- communications. Firstly, sends to a window created on a
- different thread than that from which the send is issued
- will still execute in the context of that window's thread
- and thus may incur a performance penalty due to the overhead
- involved in the required thread switch. In addition, inter
- thread sends (and API calls that result in sends to other
- threads) may result in a deadlock situation should the
- receiving thread be waiting (using say a semaphore) on some
- event from the calling thread at the time the send is
- issued. (Note that WinMsgMuxSemWait exists specifically to
- avoid this deadlock situation.) The temptation may be to
- think that creating windows each on separate threads will
- permit extensive processing without interference with the
- overall message flow, but it must be remembered that all
- threads that create a (non object) window are subject to the
- same input restrictions discussed above. It is because of
- these reasons that I propose creation of all windows on the
- initial thread and exclusive use of posts for inter thread
- communications in this document.
-
- The above brings up the important concept of distribution of
- responsibilities within the application. The model I use and
- propound herein is that the main (initial) thread be used
- almost exclusively for window 'management'. Thus ALL (non
- object) windows will be created (or 'owned') by this thread
- and any activity likely to involve more than minimal
- processing off-loaded to non-window 'service' threads. The
- main thread (simply because of the fact that this is where
- the windows were created) will be the sole 'input' thread
- subject to the keyboard/mouse message restrictions discussed
- above. All other threads can thus undertake substantial
- processing tasks (or waits) without impacting the
- application's ability to appear responsive to user
- interaction. Using this demarcation of processing
- responsibility, it is unlikely that the problem of using
- inter thread sends will arise.
-
-
- Managing threads ________________
-
- Threads (over and above the initial one allocated when the
- program begins execution) are created explicitly with
- DosCreateThread. Each thread will have its own stack
- (allocated and committed dynamically with 2.x) but share all
- code and data areas of the parent process. Optionally a 32
- bit parameter can be passed to the thread at this time and
- this is normally used to address thread initialization data
- (or 'thread parameters'). A thread so created will exist for
- the life of the program execution (process) unless it
-
-
-
- OS/2 Threads Cookbook page 9
-
-
- terminates itself by 'returning' or making a call to
- _endthread or DosExit (with EXIT_THREAD).
-
- Due to any overhead in creating/destroying a thread it is
- normal to have the thread life tied to the 'owning' window
- or dialog box or failing that, the entire process. There are
- no rules as to how many threads should be created in the
- 'average' program as this will be governed by the activity
- and resource requirements of each. One way of deciding the
- number (and more importantly, function) of threads to create
- is to consider how many of the elements of the program you
- would like to run in parallel. Thus a program which creates
- a number of windows (all of which require extensive
- graphics) plus provides for background printing may create a
- thread for each window, with another for servicing the
- printer queue. Or maybe all the windows could share a single
- drawing thread if the processing requirements are smaller.
- The final consideration of thread numbers and function will
- depend on both the degree of interactivity and visible feel
- the programmer wishes to create with the program and how
- logically functions are isolated internally in the program
- itself. (Realistically, the same end result may be achieved
- by creating only a single 'service' thread in addition to
- the main thread and alternately allocating time to the
- respective resources, but maintaining the desired balance
- may require duplicating the function of the OS/2 scheduler
- itself, and hence be self defeating.)
-
- A number of other API calls are related to threads.
- DosWaitThread (new with 2.x) allows the thread 'owner'
- (actually any thread) to wait until the specified thread is
- terminated and thus can be used when the owner itself is
- being destroyed for clean-up operations. DosSuspendThread
- and DosResumeThread allow another thread to temporarily halt
- execution of the specified thread, and resume operation at a
- later time. Due to the fact that it will probably not be
- possible to predict the exact stage of operation of the
- specified thread, these calls may not prove to be that
- useful, and indeed a similar effect can be achieved by
- resetting that thread's priority. DosSetPriority can be used
- to modify a thread's priority, or to place the thread in a
- different dispatching class. DosKillThread (also new with
- 2.x) can be used to terminate secondary threads but at the
- risk of leaving allocated resources used by that thread.
- DosEnterCritSec and DosExitCritSec can be used to
- temporarily disallow execution of all other threads in the
- process when serialized access to a resource of some type
- must be guaranteed, and using mutex semaphores is not
- appropriate. Finally, DosSleep can be used by a thread to
- surrender the remainder of its dispatching time slice or to
- delay execution for a specified amount of time.
-
- In addition to the above, OS/2 has a rich set of inter-
- process communication facilities, such as semaphores and
-
-
-
- OS/2 Threads Cookbook page 10
-
-
- pipes which may be used for thread control and transferring
- data between threads.
-
-
- DosCreateThread vs. _beginthread ________________________________
-
- No paper on OS/2 threads programming would be complete
- without a discussion on the differences between the use of
- the API function DosCreateThread and the replacement C
- compiler run-time extension _beginthread.
-
- The problem with using DosCreateThread in a C program is
- that a number of C run-time library and inline functions
- assume a single instance of internal static variables and
- the behaviour of the program may be undefined when this
- common data is accessed by two or more threads concurrently.
- Such functions include malloc/free, strtok and rand. The
- standard malloc/free functions, for example, assume
- unrestricted access to the heap management control
- information and corruption may occur if access to this
- information is preempted by a second thread requesting
- access to the same data. The strtok and rand functions both
- save their current state between calls which may result in
- indeterministic behaviour due to dynamics in access of
- threads to the previous state.
-
- The solution adopted by a number of vendors of C compilers
- has been to prevent these undesirable effects by either
- serializing access to such data that must be shared, or
- providing an individual instance of the data for each thread
- created. This is achieved firstly by performing some run-
- time initialization of localized thread variables with
- _beginthread prior to invoking the DosCreateThread function.
- Secondly, a number of run-time functions are modified to
- either access these local variables or request serialization
- (with DosRequestMutexSem or DosEnterCritSec) when the data
- must be shared. To the programmer, such management is
- transparent provided that the _beginthread function is used
- exclusively and the program is linked with the appropriate
- multi-threading run-time library.
-
- An alternative solution to the above approach is to restrict
- a program's use of functions to those documented to be
- reentrant. True reentrant routines will use a stack-based
- local copy of any data (where required) and thus avoid any
- contention from other threads as each has its own individual
- stack. The IBM C Set/2 Subsystem run-time library (with the
- heap management functions replaced with use of OS/2
- suballocation routines) may well support this alternative.
- Such may be desired to minimize the run-time overhead in
- providing contention support when none is desired.
-
-
-
- OS/2 Threads Cookbook page 11
-
-
- Both examples below use _beginthread for creation of threads
- and are compiled with the multi-threading switch and linked
- with the supporting run-time library.
-
-
- Window data ___________
-
- Each window procedure associated with a window class will
- have some data to be retained over the life of the window,
- or between processing of messages. This 'static' data can be
- initialized when the window procedure receives its WM_CREATE
- or WM_INITDLG message and updated depending on subsequent
- message flow. It is common practise to place such 'static'
- data in a dynamically allocated area of memory and have this
- addressed by a window 'pointer'. Thus an area of the
- appropriate size will be allocated (with malloc) when the
- window is created and the address of this area saved in a
- window 'word' with WinSetWindowPtr. The address of this area
- will be retrieved with WinQueryWindowPtr immediately prior
- to processing of all other messages for the window, and the
- memory area disposed of (with free) in WM_DESTROY
- processing. Thus if multiple 'instances' of the window are
- created, each window can be assured of integrity of its own
- data. This can have an added benefit in reducing the total
- EXE file size, and more importantly promotes what I believe
- to be a good 'object oriented' programming style. Though not
- directly related to using threads, the concept of data
- encapsulation will be rigidly exploited in the coding
- examples contained herein.
-
-
- Example 1 _________
-
- The first example below is the complete window procedure for
- a file search dialog. This dialog provides the user with a
- means to search a number of disks for a specified file, or
- ones matching the given 'mask' criteria. The user enters the
- desired file name (with or without free characters), selects
- a number of disks and presses the 'start' button. Once the
- search is initiated, the 'start' button changes its function
- to 'stop' to enable the user to interrupt the active search.
- As files are found that match the search criteria, they will
- be added to a list box which can be scrolled and an entry
- selected even though the search is still active, enabling
- the user to exit with the selected file without waiting for
- the search to complete. The 'stop' button reverts to its
- 'start' function when the search is complete. Whilst this
- search is in progress, the user can move the dialog window
- or interact with other applications on the desktop.
-
- The virtue of using a separate thread for this type of
- dialog is that the I/O intensive logic for scanning the
- directory list(s) for the specified files can be segregated
- from that of interacting with the user. The end result is
-
-
-
- OS/2 Threads Cookbook page 12
-
-
- that maximum flexibility of interaction is achieved without
- impacting the speed of the actual search.
-
-
- This dialog window procedure creates the search thread in
- the WM_INITDLG processing and terminates the thread in
- WM_DESTROY, thus the thread exists for the life of the
- dialog session. The search thread issues a mux wait on two
- event semaphores: a 'trigger' to initiate a new search and a
- 'terminate' event to signal thread termination. Once the
- search is active, it can be interrupted by setting the
- fInterrupt flag TRUE, and this flag is checked periodically
- in the search process.
-
- As files are found that match the specified criteria, the
- search thread posts a UM_SEARCHUPDATE message to the
- 'owning' thread to signal that the found entry should be
- added to the list box. In this case, we cannot use the
- message parameters on the post to fully contain the data to
- be transferred as the file name length clearly exceeds the
- eight bytes available. What has been done in this example is
- to use a simplified form of circular buffer, with an 'in'
- and 'out' count. Thus entries can be added to the buffer
- when the 'in' count does not exceed the 'out' count by the
- total number of entries in the buffer, otherwise we would
- overlay data that had not been accepted by the owning
- thread. As the buffer and counters are accessible by both
- threads, all that is required is to signal the owning thread
- that new data has been added to the list and should be
- processed. This is done here by equating UM_SEARCHUPDATE to
- WM_SEM2 and using message parameter 1 as a progress flag,
- with TRUE indicating completion of the search. The WM_SEM1-4
- messages are special in that the messages are not stacked in
- the message queue, but accumulated into one message with the
- message parameter 1 seen by the recipient being the OR'ed
- result from all the messages parameters posted. WM_SEM2
- (rather than WM_SEM1) was selected as the priority of this
- message is lower than that of keyboard/mouse messages thus
- avoiding any impact on user interaction whilst transferring
- data. (If you move the mouse pointer around rapidly you will
- notice that the search will slow down.)
-
- A few other observations on this example. Because of the
- nature of the WM_SEMx messages, there is no risk of flooding
- the application message queue (and hence losing a post) in
- that there can be only one message of this type in the queue
- at any time. Also, it is likely that a number of found
- entries can be transferred for each post the main thread
- sees, hence improving the efficiency of the transfer. If the
- circular buffer is full (indicated by the value of the
- difference in the counters) the search thread issues
- DosSleep to surrender the remainder of its dispatching time
- slice and thus allowing the main thread to process the
- queued entries and free up the slots required.
-
-
-
- OS/2 Threads Cookbook page 13
-
-
-
- Another important element is that the dialog window
- procedure has been structured to not have to depend
- synchronously on the action of the search thread, allowing
- the search to be interrupted and end without the main thread
- logic having to issue a wait. If it is possible to avoid
- such waits, an extra level of semaphore handshaking can be
- omitted.
-
-
- Example 2 _________
-
- The second example is a window procedure (together with its
- 'service' thread) for utilizing 'shadow' bitmaps to
- facilitate fast paints and to off-load the bulk of the
- processing requirement to a 'non input' thread. A shadow
- bitmap (as used in this example) is the context for the
- drawing operations which can proceed offline from the main
- window procedure and be quickly transferred to the window
- context with GpiBitBlt in the WM_PAINT method. This
- implementation is ideal when an application can present the
- completed drawing, rather than show the drawing activity in
- progress. Also, if the destination window is to be restored
- (eg. after being covered by another) a subsequent call to
- the processor intensive graphics functions is avoided.
-
- This example differs from the first in that the service
- thread allocates its own message queue, and communications
- between threads is achieved with posts (rather than
- semaphores). Thus, a request for some activity can be
- 'queued' to the service thread (with WinPostQueueMsg) by
- specifying the handle of the message queue itself. Note that
- WinPostMsg could not be used in this case as the service
- thread has not actually created any windows and hence no
- window handle exists to enable PM to determine which queue
- is applicable. The service thread has its own message loop
- to un-queue the posted requests and route to the appropriate
- logic based on message ID, and in this sense is no different
- from a normal window procedure. When the activity is
- complete, the service thread posts a completion message to
- the 'owning' thread to trigger the appropriate action (eg.
- paint). Lastly, the service thread is terminated by posting
- WM_QUIT to its message queue which causes the loop to
- terminate.
-
- The service thread in this example exists for the life of
- its 'owning' window, created in WM_CREATE and terminated in
- WM_DESTROY. As the main procedure must insure that the
- service thread's message queue is valid, a semaphore is set
- by the service thread when the queue handle is available to
- its owner.
-
- If multiple instances of this window are required, each will
- have its own service thread and this enables a priority
-
-
-
- OS/2 Threads Cookbook page 14
-
-
- mechanism to exist to ensure that the active window will be
- drawn before other, non-active windows. This is achieved in
- this example buy raising or lowering the service thread
- priority (in WM_ACTIVATE) so that the active window's
- priority is always higher that its siblings. The priority
- mechanism is absolute in that the service thread for the
- active window must 'block' (in WinGetMsg) before the other
- windows will receive any processor resource. Note that as
- implemented in this example this set priority will still be
- lower than that of the main 'input' thread to reduce any
- interference with desktop operations.
-
- When using this message queue technique, it is possible to
- optionally check for pending messages posted in the queue
- with a call to WinQueryQueueStatus. In this example, as all
- output posts from the service thread are the same, some
- processing may be saved if processing of the current message
- is aborted in favour of pending messages of the same type.
- This should only be attempted when it can be quaranteed that
- the sequence of incoming messages is not disturbed.
-
- This example has been structured so that the main window
- thread never has to explicitly wait for completion of a
- posted task (other than for thread termination and recovery
- from failed posts). If serialization is necessary,
- semaphores 'posted' by the service thread can be used to
- delay execution until desired. Alternatively, the main
- thread can wait for a posted completion message by using
- WinGetMsg and specifying the message identity. In the
- example given
-
- WinGetMsg (pw->hab, &qmsg, (HWND) hwnd,
- UM_WINDOWUPDATE, UM_WINDOWUPDATE);
-
- would delay the main thread until the requested service was
- complete. Note that either of the above (using semaphores or
- waiting for completion messages) issued from the main input
- thread will have the effect of stopping flow in the main
- message queue of the program, and delay incoming keyboard
- and mouse messages system-wide (as discussed above). The
- goal should thus be to structure the program so that such
- serialized dependencies are minimized (or ideally avoided).
-
-
- Other possibilities ___________________
-
- The above two examples represent a sample of the
- possibilities of managing program activity with multiple
- threads. A number of other methodologies exist which may
- prove applicable to different program requirements.
-
- A variation on the shadow bitmap example above is to give
- drawing control of the window presentation space to a
- service thread. This has the similar benefit in that
-
-
-
- OS/2 Threads Cookbook page 15
-
-
- processor intensive graphics functions can be off-line from
- the main input thread with the bonus that the application
- user can see the drawing in progress, rather than wait for
- the shadow bitmap to be completed. To do this the program
- would (probably in WM_CREATE) associate a presentation space
- to the window context with WinOpenWindowDC and GpiCreatePS
- and pass this presentation space handle to the drawing
- thread. The drawing thread would thus receive requests from
- the main thread and invoke the graphics functions required
- to draw directly upon the window presentation space. Some
- provision may need to be made for retaining the results of
- the drawing activity should a full or partial re-paint be
- required due to window sizing or restoral.
-
- An extension of using threads with their own message queue
- is to create object windows (windows created with a parent
- of HWND_OBJECT). Activity in such 'windows' is initiated
- with WinPostMsg as the object window handle is specified to
- identify the appropriate message queue and window procedure
- for that window. In all other respects, this is identical to
- the message queue example above. The use of object windows
- may be applicable when a thread exists to support a number
- of resources and no overlap in processing is required.
-
-
- Conclusion __________
-
- It is hoped that by now the reader has understood the
- fundamentals of why multiple threads are applicable to OS/2
- Presentation Manager programs for improving the overall
- responsiveness of the desktop dictated by the message queue
- architecture, and the implications for presentation of a
- flexible user-application interface. The existence of
- threads in OS/2 provides the application designer with a
- rich set of techniques to distribute function within the
- program itself and co-ordinate activity. The goal of the
- application designer should be to identify opportunities for
- parallel operation, and to build the program with the
- appropriate threads to achieve this, whilst allowing the
- user to interrupt or abort any lengthy activity in progress.
-
- Multiple threads, I feel, offer the means to totally
- transform a user's expectation of how personal computer
- software should work and hopefully this document will help
- bring about this new age of more responsive and flexible
- software.
-
-
-
- OS/2 Threads Cookbook page 16
-
-
-
- References __________
-
- The following references may be useful in expanding the
- reader's understanding of OS/2 multi-threading techniques
- and possibilities as applicable to Presentation Manager
- programming:
-
-
-
- Utilizing OS/2 Multithread Techniques in Presentation _____________________________________________________
- Manager Applications, Charles Petzold ____________________
-
- Microsoft Systems Journal Vol. 3 No. 2
-
-
- Planning and Writing a Multithreaded OS/2 Program with ______________________________________________________
- Microsoft C, Richard Hale Shaw ___________
-
- Microsoft Systems Journal Vol. 4 No. 2
-
-
- OS/2 PM Programming: A Performance Guide, P.G. Toghill ________________________________________
-
- IBM Personal Systems Developer, Winter 1991
-
-
- A Multithread CPU Monitor, Marc Cohen _________________________
-
- OS/2 Notebook, The Best of the IBM Personal Systems
- Developer, Microsoft Press
-
-
- Programming for Multithreaded Drawing, Charles Petzold _____________________________________
-
- PC Magazine, Vol. 9 Nos. 10-12
-
-
- Programming the OS/2 Presentation Manager, Charles Petzold _________________________________________
-
- Microsoft Press
-
-
- Inside OS/2, Gordon Letwin ___________
-
- Microsoft Press
-
-
- Microsoft OS/2 Programmer's Reference Vol. 1 ____________________________________________
-
- Microsoft Press
-
-
-
- OS/2 Threads Cookbook page 17
-
-
-
-
-
- Programming Guide _________________
-
- IBM OS/2 Programming Tools and Information, Version 1.2
-
-
- The Design of OS/2, H.M. Deitel and M.S. Kogan __________________
-
- Addison-Wesley
-
-
- IBM C Set/2 User's Guide ________________________
-
- IBM Publication number S10G-4444-0
-