📄 mthread.gml
字号:
#define STACK_SIZE 32768
.code break
static void a_thread( void *arglist )
/***********************************/
{
while( HoldThreads ) {
DosSleep( 1 );
}
printf( "Hi from thread %d\n", *_threadid );
DosEnterCritSec();
--NumThreads;
DosExitCritSec();
_endthread();
}
.code break
int main( void )
/**************/
{
int i;
printf( "Initial thread id = %d\n", *_threadid );
NumThreads = 0;
HoldThreads = 1;
/* initial thread counts as 1 */
for( i = 2; i <= NUM_THREADS; ++i ) {
if( _beginthread( a_thread, NULL, STACK_SIZE, NULL ) == -1 ) {
printf( "creation of thread %d failed\n", i );
} else {
++NumThreads;
}
}
.code break
HoldThreads = 0;
while( NumThreads != 0 ) {
DosSleep( 1 );
}
return( 0 );
}
.code end
.do end
.autonote Note:
.note
In the &function
.id a_thread,
.id DosEnterCritSec
and
.id DosExitCritSec
are called when we modify the variable
.id NumThreads.
This ensures that the action of extracting the value of
.id NumThreads
from memory, incrementing the value, and storing the new result into
memory, occurs without interruption.
If these functions were not called, it would be possible for two
threads to extract the value of
.id NumThreads
from memory before an update occurred.
.endnote
.do end
.*
.if '&targetos' eq 'Windows NT' .do begin
.if '&lang' eq 'FORTRAN 77' .do begin
The source code for this example can be found in
.fi &pathnam.\samples\fortran\win32.
.code begin
* MTHREAD.FOR
*$pragma aux (__stdcall) Sleep parm( value )
*$pragma aux (__stdcall) InitializeCriticalSection parm( reference )
*$pragma aux (__stdcall) DeleteCriticalSection parm( reference )
*$pragma aux (__stdcall) EnterCriticalSection parm( reference )
*$pragma aux (__stdcall) LeaveCriticalSection parm( reference )
structure /RTL_CRITICAL_SECTION/
integer*4 DebugInfo
integer*4 LockCount
integer*4 RecursionCount
integer*4 OwningThread
integer*4 LockSemaphore
integer*4 Reserved
end structure
.code break
integer NumThreads
logical HoldThreads
volatile HoldThreads, NumThreads
record /RTL_CRITICAL_SECTION/ CriticalSection
common NumThreads, HoldThreads, CriticalSection
integer STACK_SIZE
parameter (STACK_SIZE=8192)
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
call InitializeCriticalSection( CriticalSection )
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 Sleep( 1 )
end while
call DeleteCriticalSection( CriticalSection )
end
.code break
subroutine a_thread()
structure /RTL_CRITICAL_SECTION/
integer*4 DebugInfo
integer*4 LockCount
integer*4 RecursionCount
integer*4 OwningThread
integer*4 LockSemaphore
integer*4 Reserved
end structure
.code break
integer NumThreads
logical HoldThreads
volatile HoldThreads
record /RTL_CRITICAL_SECTION/ CriticalSection
common NumThreads, HoldThreads, CriticalSection
integer threadid
.code break
while( HoldThreads ) do
call Sleep( 1 )
end while
.code break
print '(''Hi from thread '', i4)', threadid()
call EnterCriticalSection( CriticalSection )
NumThreads = NumThreads - 1
call LeaveCriticalSection( CriticalSection )
call endthread()
end
.code end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.code begin
#include <process.h>
#include <stdio.h>
#include <stddef.h>
#include <windows.h>
static volatile int NumThreads;
static volatile int HoldThreads;
CRITICAL_SECTION CriticalSection;
#define NUM_THREADS 5
#define STACK_SIZE 8192
.code break
static void a_thread( void *arglist )
/***********************************/
{
while( HoldThreads ) {
Sleep( 1 );
}
printf( "Hi from thread %d\n", *_threadid );
EnterCriticalSection( &CriticalSection );
--NumThreads;
LeaveCriticalSection( &CriticalSection );
_endthread();
}
.code break
int main( void )
/**************/
{
int i;
printf( "Initial thread id = %d\n", *_threadid );
NumThreads = 0;
HoldThreads = 1;
InitializeCriticalSection( &CriticalSection );
/* initial thread counts as 1 */
for( i = 2; i <= NUM_THREADS; ++i ) {
if( _beginthread( a_thread, STACK_SIZE, NULL ) == -1 ) {
printf( "creation of thread %d failed\n", i );
} else {
++NumThreads;
}
}
.code break
HoldThreads = 0;
while( NumThreads != 0 ) {
Sleep( 1 );
}
DeleteCriticalSection( &CriticalSection );
return( 0 );
}
.code end
.do end
.autonote Note:
.note
In the &function
.id a_thread,
.id EnterCriticalSection
and
.id LeaveCriticalSection
are called when we modify the variable
.id NumThreads.
This ensures that the action of extracting the value of
.id NumThreads
from memory, incrementing the value, and storing the new result into
memory, occurs without interruption.
If these functions were not called, it would be possible for two
threads to extract the value of
.id NumThreads
from memory before an update occurred.
.endnote
.do end
.np
Let us assume that the file
.fi &tgtfile..&langsuff
contains the above example.
Before compiling the file, make sure that the
.ev &pathvarup.
environment variable is set to the directory in which you installed
&product..
.if '&lang' eq 'FORTRAN 77' .do begin
Also, the
.ev FINCLUDE
environment variable must contain the
.if '&targetos' eq 'OS/2 2.x' .do begin
.fi &pathnam\src\fortran\os2
.do end
.el .do begin
.fi &pathnam\src\fortran
.do end
directory where "&pathnamup" is the name of the directory in which you
installed &product..
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
Also, the
.ev INCLUDE
environment variable must include the
.if '&targetos' eq 'OS/2 2.x' .do begin
.fi &pathnam\h\os2
.do end
.el .do begin
.fi &pathnam\h\nt
.do end
and
.fi &pathnam\h
directories
("&pathnamup" is the directory in which &product was installed).
.do end
.np
We can now compile and link the application by issuing the following
command.
.millust begin
&prompt.&wclcmd &tgtopts &sw.l=&tgtosname &tgtfile
.millust end
.np
The "bm" option must be specified since we are creating a
multi-threaded application.
If your multi-threaded application contains more than one module, each
module must be compiled using the "bm" switch.
.np
The "l" option specifies the target system for which the application
is to be linked.
The system name
.id &tgtosname
is defined in the file
.fi wlsystem.lnk
which is located in the "BINW" subdirectory of the directory in which you
installed &product..
.np
The multi-threaded application is now ready to be run.
.*
.if '&targetos' eq 'OS/2 2.x' .do begin
.section Thread Limits
.*
.np
.ix 'thread limits' '&targetos.'
There is a limit to the number of threads an application can create
under 16-bit OS/2.
The default limit is 32.
.if '&lang' eq 'FORTRAN 77' .do begin
This limit can be adjusted by defining the integer function
.id __getmaxthreads
which returns the new thread limit.
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
This limit can be adjusted by statically initializing the unsigned
global variable
.id __MaxThreads.
.do end
.np
Under 32-bit OS/2, there is no limit to the number of threads an
application can create.
However, due to the way in which multiple threads are supported in the
&company libraries, there is a small performance penalty once the number
of threads exceeds the default limit of 32 (this number includes the
initial thread).
If you are creating more than 32 threads and wish to avoid this
performance penalty, you can redefine the threshold value of 32.
You can statically initialize the global variable
.id __MaxThreads.
.np
.if '&lang' eq 'FORTRAN 77' .do begin
This limit can be adjusted by defining the integer function
.id __getmaxthreads
which returns the new thread limit.
By defining
.id __getmaxthreads
as follows, the new threshold value will be set to 48.
.millust begin
integer function __getmaxthreads()
__getmaxthreads = 48
end
.millust end
.np
This version of
.id __getmaxthreads
will replace the default function that is included in the run-time
library.
The default function simply returns the current value of the internal
variable
.id __MaxThreads.
Your version of this function will return a new value for this
variable.
Internally, the run-time system executes code similar to the
following:
.millust begin
.
.
.
__MaxThreads = __getmaxthreads()
.
.
.
.millust end
.np
Thus, the default
.id __getmaxthreads
function does not alter the value of
.id __MaxThreads
but your version will.
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
By adding the following line to your multi-threaded application, the
new threshold value will be set to 48.
.millust begin
unsigned __MaxThreads = { 48 };
.millust end
.do end
.*
.do end
.*
:set symbol="prompt" value=&oprompt.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -