⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mthread.gml

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 GML
📖 第 1 页 / 共 2 页
字号:
:set symbol="oprompt"    value=&prompt.
.if '&targetos' eq 'OS/2 2.x' .do begin
:set symbol="prompt"    value="[C:\]".
:set symbol="tgtosname" value="os2v2".
.do end
.el .do begin
:set symbol="prompt"    value="C:\>".
:set symbol="tgtosname" value="nt".
.do end
:set symbol="tgtfile" value="mthread".
.*
.if '&lang' eq 'FORTRAN 77' .do begin
:set symbol="tgtopts"   value="&sw.bm".
:set symbol="include" value="include".
:set symbol="begthread" value="beginthread".
:set symbol="endthread" value="endthread".
:set symbol="threadid" value="threadid".
:set symbol="threadacc" value="function".
:set symbol="null" value="0".
:set symbol="function" value="subroutine".
:set symbol="thrdincl" value="thread.fi".
:set symbol="idincl" value="thread.fi".
:set symbol="routine" value="subroutine".
.do end
.*
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.   .if '&targetos' eq 'OS/2 2.x' .do begin
:set symbol="tgtopts"   value="&sw.bt=os2 &sw.bm".
.   .do end
.   .el .do begin
:set symbol="tgtopts"   value="&sw.bt=nt &sw.bm".
.   .do end
:set symbol="include" value="header".
:set symbol="begthread" value="_beginthread".
:set symbol="endthread" value="_endthread".
:set symbol="threadid" value="_threadid".
:set symbol="threadacc" value="variable/macro".
:set symbol="threadacc" value="macro".
:set symbol="null" value="NULL".
:set symbol="function" value="function".
:set symbol="thrdincl" value="process.h".
:set symbol="idincl" value="stddef.h".
:set symbol="routine" value="function".
.do end
.*
.chap &targetos Multi-threaded Applications
.*
.np
.ix 'multi-threaded applications' '&targetos.'
This chapter describes how to create multi-threaded applications.
A multi-threaded application is one whose tasks are divided among several
threads of execution.
.ix 'threads of execution'
A process is an executing application and the resources it uses.
.ix 'multi-threaded applications'
A thread is the smallest unit of execution within a process.
Each thread has its own stack and a set of machine registers and
shares all resources with its parent process.
The path of execution of one thread does not affect that of another;
each thread is an independent entity.
.np
Typically, an application has a single thread of execution.
In this type of application, all tasks, once initiated, are completed
before the next task begins.
In contrast, tasks in a multi-threaded application can be performed
concurrently since more than one thread is executing at once.
For example, each thread may be designed to perform a separate task.
.*
.section Programming Considerations
.*
.np
.ix 'multi-threading issues' '&targetos.'
Since a multi-threaded application consists of many threads of execution,
there are a number of issues that you must consider.
.np
Since threads share the resources of its parent, it may be necessary
to serialize access to these resources.
.if '&lang' eq 'FORTRAN 77' .do begin
For example, if your application contains more than one thread of
execution and each thread uses the
.kw PRINT
statement to display output to the console, it would be necessary for
the I/O support routines to allow only one thread to use the
.kw PRINT
facility at any time.
That is, once a thread issues a
.kw PRINT
request, the I/O support routines should ensure that no other thread
displays information until all information for the initial thread has
been displayed.
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
For example, if your application has a function that displays
information on the console and is used by all threads, it is necessary
to allow only one thread to use that function at any time.
That is, once a thread calls that function, the function should ensure
that no other thread displays information until all information for
the initial thread has been displayed.
An example of such a function is the
.id printf
library function.
.np
Another issue that must be considered when creating multi-threaded
applications is global variables.
If you have global variables that contain thread-specific information,
there must be an instance of each global variable for each thread.
An example of such a variable is the
.id errno
global variable defined in the run-time libraries.
If an error condition was created by a thread, you would not want it
to affect the execution of other threads.
Therefore, each thread should contain its own instance of this
variable.
.do end
.*
.section Creating Threads
.*
.np
.ix 'thread creation' '&targetos.'
Each application initially contains a single thread.
The run-time libraries contain two functions that create and terminate
threads of execution.
The function
.id &begthread
creates a thread of execution and the function
.id &endthread
ends a thread of execution.
The &threadacc
.id &threadid
can be used to determine the current thread identifier.
.np
.warn
If any thread
.if '&lang' eq 'FORTRAN 77' .do begin
uses an I/O statement or calls an intrinsic function,
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
calls a library function,
.do end
you must use the
.id &begthread
function to create the thread.
Do not use the
.if '&targetos' eq 'OS/2 2.x' .do begin
.id DosCreateThread
.do end
.el .do begin
.id CreateThread
.do end
API function.
.ewarn
.*
.beglevel
.*
.section Creating a New Thread
.*
.np
.ix 'thread creation' '&targetos.'
.ix '&begthread function'
The
.id &begthread
function creates a new thread.
It is defined as follows.
.if '&lang' eq 'FORTRAN 77' .do begin
.millust begin
integer function beginthread( start_address,
                              stack_size )
integer stack_size
end
.millust end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.if '&targetos' eq 'OS/2 2.x' .do begin
.millust begin
int _beginthread( void (*start_address)(void *),
                  void *stack_bottom,
                  unsigned stack_size,
                  void *arglist );
.millust end
.do end
.el .do begin
.millust begin
unsigned long _beginthread( void (*start_address)(void *),
                            unsigned stack_size,
                            void *arglist);
.millust end
.do end
.do end
.synote
.mnote start_address
is the address of the &function that will be called when the newly
created thread is executed.
When the thread returns from that &function, the thread will be
terminated.
Note that a call to the
.id &endthread
&routine will also terminate the thread.
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.if '&targetos' eq 'OS/2 2.x' .do begin
.mnote stack_bottom
specifies the bottom of the stack to be used by the thread.
Note that this argument is ignored as it is only needed to simplify
the port of OS/2 1.x multi-threaded applications to &targetos..
Under &targetos, the operating system allocates the stack for the new
thread.
A value of NULL may be specified.
.do end
.do end
.mnote stack_size
specifies the size of the stack to be allocated by the operating
system for the new thread.
The stack size should be a multiple of 4K.
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.mnote arglist
is passed as an argument to the &function specified by
.id start_address.
If no argument is required, a value of &null can be specified.
.do end
.esynote
.np
If a new thread is successfully created, the thread identifier of the
new thread is returned.
Otherwise, a value of -1 is returned.
.np
The &include file
.fi &thrdincl
contains the definition of the
.id &begthread
function.
.if '&targetos' eq 'Windows NT' .do begin
.np
Another thread related function for &targetos is
.id _beginthreadex.
See the
.book &company C Library Reference
for more information.
.do end
.*
.section Terminating the Current Thread
.*
.np
.ix 'thread termination' '&targetos.'
.ix '&endthread &routine'
The
.id &endthread
&routine terminates the current thread.
It is defined as follows.
.if '&lang' eq 'FORTRAN 77' .do begin
.millust begin
subroutine endthread()
end
.millust end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.millust begin
void _endthread( void )
.millust end
.do end
.np
The &include file
.fi &thrdincl
contains the definition of the
.id &endthread
function.
.*
.section Getting the Current Thread Identifier
.*
.np
.ix 'thread identifier' '&targetos.'
.ix '&threadid &threadacc'
The
.id &threadid
&threadacc can be used to determine the current thread identifier.
It is defined as follows.
.if '&lang' eq 'FORTRAN 77' .do begin
.millust begin
integer function threadid()
end
.millust end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.millust begin
int *__threadid(void);
#define _threadid (__threadid())
.millust end
.do end
.np
The &include file
.fi &idincl
contains the definition of the
.id &threadid
&threadacc..
.*
.endlevel
.*
.section A Multi-threaded Example
.*
.np
.ix 'thread example' '&targetos.'
Let us create a simple multi-threaded application.
.if '&targetos' eq 'OS/2 2.x' .do begin
.if '&lang' eq 'FORTRAN 77' .do begin
The source code for this example can be found in
.fi &pathnam.\samples\fortran\os2.
.code begin
* MTHREAD.FOR

*$pragma aux DosSleep parm( value ) [] caller

      integer NumThreads
      logical HoldThreads
      common NumThreads, HoldThreads

      integer STACK_SIZE
      parameter (STACK_SIZE=32768)
      integer NUM_THREADS
      parameter (NUM_THREADS=5)

      integer i, threadid, beginthread
      external a_thread

.code break
      print '(''main thread id = '', i4)', threadid()
      NumThreads = 0
      HoldThreads = .true.
      ! main thread counts as 1
      do i = 2, NUM_THREADS
          if( beginthread( a_thread, STACK_SIZE ) .eq. -1 )then
              print '(''creation of thread'', i4, ''failed'')', i
          else
              NumThreads = NumThreads + 1
          end if
      end do
.code break
      HoldThreads = .false.
      while( NumThreads .ne. 0 )do
          call DosSleep( 1 )
      end while
      end

.code break
      subroutine a_thread()
      integer NumThreads
      logical HoldThreads
      common NumThreads, HoldThreads
      integer threadid
      while( HoldThreads )do
          call DosSleep( 1 )
      end while
.code break
      call DosEnterCritSec()
      print '(''Hi from thread '', i4)', threadid()
      NumThreads = NumThreads - 1
      call DosExitCritSec()
      call endthread()
      end
.code end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
The source code for this example can be found in
.fi &pathnam.\samples\os2.
.code begin
#include <process.h>
#include <stdio.h>
#include <stddef.h>
#define INCL_DOS
#include <os2.h>

static  volatile int    NumThreads;
static  volatile int    HoldThreads;

#define NUM_THREADS     5

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -