HomeMagiCTest for MagiCAdditional programs for MagiC

11.18 Threads in MagiC

The concept of threads enables a sort of parallel working within an application, and has been known for some time in operating systems such as OS/2, MacOS or UNIX. In contrast to normal multitasking, it is possible for several threads to belong to a program (or process). In MagiC threads are supported from version 4.50 (01.04.96) onwards, and are implemented as an application, i.e. a thread under MagiC posseses its own application ID. The concept here is based on that of Sun Solaris 2.x.

This section describes the following points:

See also: About the GEMDOS   Process functions   Example

11.18.1 Threads and signals

If a process is paused with the signal SIGSTOP or similar then all threads are paused as well; with SIGCONT all threads are reawakened. When terminating a program with SIGTERM, SIGKILL etc. all threads are terminated too.

The signal handling will be taken over entirely by the main thread, i.e. the one that was started with Pexec. This means that during the processing of a signal-handler only the main thread will be paused, and at Psigreturn one will jump back to it.

If more than one thread is mucking about with the signal mask then oddities can occur if the old signal mask is not restored in the correct order. For instance:

Thread A rescues the old mask
Thread A alters the mask
Thread B rescues the old mask
Thread A restores the old mask
Thread B restores the old mask

This alters the signal mask in an unwanted manner. A clean solution would be to give each thread its own signal mask and OR-combine all masks of all threads for the effective signal mask. If this becomes necessary the author has said he will alter the kernel appropriately.

See also: Threads in MagiC   Signals   shel_write   Process functions

11.18.2 Threads and AES calls

In the development of users' own programs, it is imperative that a multithread-safe library is used. The standard libraries of, say, Pure-C are largely unusable in this respect. In particular one must ensure that each thread is assigned its own global field. Hence the following functions are affected:

Note: The original MagiC documentation contains examples for multithread-capable AES functions, on whose structure one may orient oneself. One should also note that the name of a thread is invalid on the AES plane, i.e. it cannot be found with appl_find or appl_search.

See also:
Threads and VDI calls   Process functions   AES bindings   Signals

11.18.3 Threads and VDI calls

VDIcalls are generally not as 'critical' as AES calls, as reentrance problems are much rarer here.

The reason is due to the fact that a call of VDI functions does not lead to task-switching as frequently as happens with AES calls, for instance.

VDIcalls however can be problematic in this respect whenever vector fonts are accessed, as in that case one normally requires disk access; these, as is generally known, are interruptible in MagiC. In such a situation a task-switch may happen. Which VDI commands individually are interruptible cannot be answered here; if required, this should be clarified with the NVDI developers, so that then reentrant library functions would be required for only those functions.

See also:
Threads and AES calls   Process functions   VDI bindings   Signals

11.18.4 Apportionment of resources with threads

In MagiC, threads run in the same process, but possess their own application ID, and so are a self-contained task. The following table gives an overview of the resources that a thread possesses itself, or uses from the main program.

Threads possess The main program uses
• User stack • File handles
• Supervisor stack • Basepage
• Application ID • Memory blocks
• Resource files • Current directories, current drive
• Menu bar • Process ID (PID)
• Desktop background • Domain (MiNT/TOS)
• Window • umask
• Message queue • Current DTA
• Mouse pointer • Malloc flags
• Possibly VT52 window (selectable) • Command line and environment
• etv_term vector • Signal-handler and -mask
• Semaphores • Possibly VT52 window (selectable)

Note: As one can see, a thread thereby receives its own AP_TERM message. When using resource files, one should pay attention to the fact that the thread may use its own global field if necessary.

One should also note that any memory that the thread may allocate belongs to the process, and at termination of the thread is not freed automatically; the same applies to opened files, which are only closed on termination of the program; if necessary, this must be undertaken by the thread.

Warning: It is imperative to note that:

The function Psemaphore is already prepared for threads, and can be used both for synchronization between processes as well as between several threads of a process. On termination of a thread, all the semaphores blocked by this will be released again automatically.

If possible, only the main thread should execute a Pexec at present, but not subsidiary threads. Theoretically this is permitted, however, namely when no other thread or the main thread has called Pexec, and the main thread does not terminate itself.

The problem lies, simply, in the fact that at present the jump-back addresses with Pexec are stored not in the running process but in the parent, and the parent of the process started by the thread becomes invalid.

If a thread performs the function Pterm, then at present only this thread is terminated. One should note also that a thread may start other programs with shel_write (in parallel), and wait on their termination.

See also:
Threads and AES calls   Threads and VDI calls   Process functions   About the GEMDOS

11.18.5 Threads, Example for

#include 
#include aes.h>

WORD global[15];
WORD ap_id;
WORD fmt_id;

LONG cdecl format_thread( struct fmt_parameter *par )
{
   WORD myglobal[15];
   WORD ap_id;

   /* we do not want to fry the global-field of the main-APPL */

   ap_id = MT_appl_init(myglobal);
   (...)
}


/*********************************************************************
*
* Starts the formatting thread.
*
*********************************************************************/

WORD start_format( VOID *param )
{
   THREADINFO thi;

   if“ (fmt_id < 0)   /* thread not yet active */
   {
      thi.proc = (VOID *) format_thread;
      thi.user_stack = NULL;
      thi.stacksize = 4096L;
      thi.mode = 0;
      thi.res1 = 0L;
      fmt_id = shel_write(SHW_THR_CREATE, 1, 0,
                          (BYTE *) &thi, param);
      return(fmt_id);
   }
   else
      return(-1);    /* thread still running */
}

WORD main( VOID )
{
   if ((ap_id = MT_appl_init(global)) < 0)
      Pterm(-1);
   else
   {
      (...)
      start_format( .... );

      while(...)
         (...);

      appl_exit();
      return(0);
   }
}

See also: Threads   About the GEMDOS   Process functions   Signals


HomeMagiCTest for MagiCAdditional programs for MagiC