procptr によって指される sub は、スレッドとして始まります。
この
userdata パラメータで、
param の内容を渡されます。指定されなければ、 0 (zero) を渡されます。
スレッドとして起動した sub は、プログラムの主要部分と並行して実行されます。
OS は、別のプロセッサがあればそれに割り当てたり、1つのプロセッサ上で実行スレッドを交互に切替えることで、これを実現します。
異なるスレッドの実行順序については保証されておらず、複数生成されたスレッドが、実際に実行を開始する順序について仮定できません。
ThreadCreate からスレッドの実際の実行開始までの時間は可変であり、コンテキストに応じて長くも短くもなります (したがって、
ThreadCreate 命令文に続く一部の命令文は、スレッドが実際に起動される前に実行される可能性があります)。
最速で起動する場合には、
ThreadCreate が戻る前でもスレッド本体が実行開始することがあります。
実行中の各スレッドは、実行中のすべてのスレッド間で一意のハンドルによって識別できます。
ThreadSelf を参照してください。
閉じる前に、プログラムは、
ThreadWait を使って、開始しているすべてのスレッドの終了を待つべきです。
あるいは、スレッドの実行終了を、安全に待つ必要がない場合、
ThreadDetach を使うことができます。
しかし、もし、スレッドがまだ動いているのに、プログラムを終了させると、そのスレッドはシステムによって異常終了するでしょう。
作成されたすべてのスレッドについて、プログラムは、
ThreadWait か
ThreadDetach のいずれかを呼んで、スレッド・ハンドルに関連したシステム・リソースが、リリースされることを保証すべきです。
そうしないと、メモリかシステム・リソースが、漏れます。
スレッドの性質により、実行順序を想定することはできません。
スレッドおよびプログラムの主要部分を含む、複数のスレッドの間のデータを交換するために、ミューテックを使わなければなりません。
これらの相互排他ロックは、重大な仕事の間、単一のスレッドによって「専有」することができ、その結果、他のスレッドの実行を待たせることができます。
Mutexcreate,
Mutexlock,
Mutexunlock,
Mutexdestroy を参照下さい。
stack_size を使うと、スレッドのスタック・サイズを、システムのデフォルトから変更できます。
これは、プログラムが、大きいスタックを必要とするとき、役に立ちます。たとえば、たくさんの手順再帰のためや、スタック上で、巨大な文字列/配列を割り当てるときです。
いくつかのシステム(Linux)では、より多くのスペースが必要なら、スタックは、自動的に
stack_size を超えて増大します;
他(
Win32)では、
stack_size は、固定の最大許容量です。
スタックが拡大できないシステムでは、予約されたサイズより多くのスタックを使おうとするとき、ふるまいは未定義です。
組み込みマクロ
__FB_MT__ は、
ThreadCreate の使用時点以降のみ自動的に設定されます。
注意:
- userdata パラメーターは myThread サブの本体では使わなくても構いませんが、ヘッダーでは Any Ptr パラメーターとして宣言することは常に必須です。
この場合、ThreadCreate を呼び出すときに、対応する param パラメーターを省略できます。あるいは、不要な引数を渡すこともできます(「0」が一般的に使われるのは、この値がどのようなポインタとも直接互換性があるからです)。 2番目と 3番目の例を参照してください。
- myThread にデータを渡す必要がある場合は、Any Ptr param を使ってデータを参照できます。通常、ThreadCreate にデータを渡す前に Any Ptr への型変換(暗黙的または明示的)が必要となり、myThread の本体でデータを使う前に Any Ptr からの逆型変換が必要となります。 1 つ目の例を参照してください。
'' ミューテックスを使ってスレッド同期
'' 「MutexLock」と「MutexUnlock」を含む行コメントアウトすると、
'' スレッドは同期しません。
'' そして、データの一部は不適当な場所に表示されるかもしれません。
Const MAX_THREADS = 10
Dim Shared As Any Ptr ttylock
'' テレタイプは、与えられた位置で画面を横切ってテキストを開きます。
Sub teletype( ByRef text As String, ByVal x As Long, ByVal y As Long )
''
'' この MutexLock は、スレッドを互いを待たせて、同時させます。
'' それで、一つずつ続けることができて、出力を表示します。
'' さもなければ、その Locates は干渉します。カーソルは一つしかないからです。
''
'' どのスレッドがここに到着するか、
'' どれが、他のスレッドを待たせているロックを最初に得るか、
'' 順番を予測することは、不可能です。
''
MutexLock ttylock
For i As Integer = 0 To (Len(text) - 1)
Locate x, y + i
Print Chr(text[i])
Sleep 25, 1
Next
'' MutexUnlock はロックを出して、他のスレッドにそれを取得させます。
MutexUnlock ttylock
End Sub
Sub thread( ByVal userdata As Any Ptr )
Dim As Integer id = CInt(userdata)
teletype "Thread (" & id & ").........", 1 + id, 1
End Sub
'' ミューテックスを作成して、スレッドを同期します
ttylock = MutexCreate()
'' 子スレッドを生成
Dim As Any Ptr handles(0 To MAX_THREADS-1)
For i As Integer = 0 To MAX_THREADS-1
handles(i) = ThreadCreate(@thread, CPtr(Any Ptr, i))
If handles(i) = 0 Then
Print "Error creating thread:"; i
Exit For
End If
Next
'' これは、主スレッドです。今、すべての子スレッドが終わるのを待ちます
For i As Integer = 0 To MAX_THREADS-1
If handles(i) <> 0 Then
ThreadWait(handles(i))
End If
Next
'' Clean up when finished
MutexDestroy(ttylock)
Sleep
Sub print_dots(ByRef char As String)
For i As Integer = 0 To 29
Print char;
Sleep CInt(Rnd() * 100), 1
Next
End Sub
Sub mythread(param As Any Ptr)
'' Work (other thread)
print_dots("*")
End Sub
Randomize(Timer())
Print " main thread: ."
Print "other thread: *"
'' Launch another thread
Dim As Any Ptr thread = ThreadCreate(@mythread, 0)
'' Work (main thread)
print_dots(".")
'' Wait until other thread has finished, if needed
ThreadWait(thread)
Print
Sleep
'' Threaded consumer/producer example using mutexes
Dim Shared As Any Ptr produced, consumed
Sub consumer( ByVal param As Any Ptr )
For i As Integer = 0 To 9
MutexLock produced
Print ", consumer gets:", i
Sleep 500, 1
MutexUnlock consumed
Next
End Sub
Sub producer( ByVal param As Any Ptr )
For i As Integer = 0 To 9
Print "Producer puts:", i;
Sleep 500, 1
MutexUnlock produced
MutexLock consumed
Next i
End Sub
Dim As Any Ptr consumer_id, producer_id
produced = MutexCreate
consumed = MutexCreate
If( ( produced = 0 ) Or ( consumed = 0 ) ) Then
Print "Error creating mutexes! Exiting..."
End 1
End If
MutexLock produced
MutexLock consumed
consumer_id = ThreadCreate(@consumer)
producer_id = ThreadCreate(@producer)
If( ( producer_id = 0 ) Or ( consumer_id = 0 ) ) Then
Print "Error creating threads! Exiting..."
End 1
End If
ThreadWait consumer_id
ThreadWait producer_id
MutexDestroy consumed
MutexDestroy produced
Sleep