{{fbdoc item="title" value="THREADCREATE"}}---- Starts a user-defined procedure in a separate execution thread {{fbdoc item="syntax"}}## [[KeyPgDeclare|Declare]] [[KeyPgFunction|Function]] **Threadcreate** _ ( _ [[KeyPgByval|ByVal]] //procptr// [[KeyPgAs|As]] [[KeyPgSub|Sub]] ( [[KeyPgByval|ByVal]] //userdata// [[KeyPgAs|As]] [[KeyPgAny|Any]] [[KeyPgPtr|Ptr]] ), _ [[KeyPgByval|ByVal]] //param// [[KeyPgAs|As]] [[KeyPgAny|Any]] [[KeyPgPtr|Ptr]] = 0, _ [[KeyPgByval|ByVal]] //stack_size// [[KeyPgAs|As]] [[KeyPgInteger|Integer]] = 0 _ ) [[KeyPgAs|As]] [[KeyPgAny|Any]] [[KeyPgPtr|Ptr]] ## {{fbdoc item="usage"}}## //result// = **Threadcreate** ( //procptr// [, [ //param// ] [, //stack_size// ] ] ) ## {{fbdoc item="param"}} ##//procptr//## A pointer to the ##[[KeyPgSub|Sub]]## intended to work as a thread (see ##[[KeyPgOpProcptr|Operator ProcPtr (Procedure pointer and vtable index)]]## to get a pointer to a sub). The sub must have the following signature (same parameters, same calling convention) to be compatible to //procptr//: ##[[KeyPgDeclare|Declare]] [[KeyPgSub|Sub]] myThread ( [[KeyPgByval|ByVal]] //userdata// [[KeyPgAs|As]] [[KeyPgAny|Any]] [[KeyPgPtr|Ptr]] )## ##//userdata//## The ##Any Ptr## parameter of the ##[[KeyPgSub|Sub]]## intended to work as a thread. ""FreeBASIC"" expects this parameter to be present, it must not be omitted! ##//param//## ##Any Ptr## argument that will be passed to the thread ##[[KeyPgSub|Sub]]## pointed to by ##//procptr//## through its //userdata// parameter. For example, this can be a pointer to a structure or an array containing various information for the thread sub to work with. If //param// is not given, ##0## (zero) will be passed to the thread sub's //userdata// parameter instead. ##//stack_size//## Optional number of bytes to reserve for this thread's stack. {{fbdoc item="ret"}} **""ThreadCreate""** returns an ##Any Ptr## handle to the thread created, or a null pointer (##0##) on failure. {{fbdoc item="desc"}} The sub pointed to by //procptr// is started as a thread. It will be passed the content of //param//, or 0 (zero) if not specified, in its //userdata// parameter. The sub that was started as a thread will execute in parallel with the main part of the program. The OS achieves this by assigning it to a different processor if it exists, or by alternating between execution threads on a single processor. There is no guarantee about the order in which different threads execute, and no assumptions can be made about the order in which multiple created threads actually start executing. The time between **""ThreadCreate""** and the actual start of execution of the thread is variable and can be longer or shorter depending on the context (so some statements following the **""ThreadCreate""** statement can be executed before the actual launch of the thread). In the fastest launch cases, the thread body may start executing even before **""ThreadCreate""** returns. Each running thread can be identified by its handle which is unique among all running threads. See ##[[KeyPgThreadSelf|ThreadSelf]]##. Before closing, programs should wait for the termination of all launched threads by using ##[[KeyPgThreadWait|ThreadWait]]##. Alternatively, if it's not necessary to safely wait for a thread to finish execution, ##[[KeyPgThreadDetach|ThreadDetach]]## can be used. However, if a program exits while some threads are still active, those threads will be aborted by the system. For every thread created, programs should call either ##[[KeyPgThreadWait|ThreadWait]]## or ##[[KeyPgThreadDetach|ThreadDetach]]## to ensure that the system resources associated with the thread handles are released. Otherwise, there may be memory or system resource leaks. Due to the nature of threads, no assumptions about execution order can be made. In order to exchange data between multiple threads, including a thread and the main part of the program, mutexes must be used. These mutual exclusion locks can be "owned" by a single thread while doing critical work, causing other threads to wait for their turn. See ##[[KeyPgMutexCreate|Mutexcreate]]##, ##[[KeyPgMutexLock|Mutexlock]]##, ##[[KeyPgMutexUnlock|Mutexunlock]]##, ##[[KeyPgMutexDestroy|Mutexdestroy]]##. ##//stack_size//## can be used to change the thread's stack size from the system's default. This can be useful when the program requires a big stack, for example due to lots of procedure recursion or when allocating huge strings/arrays on the stack. On some systems (Linux), the stack automatically grows beyond ##//stack_size//## if more space is needed; on others (Win32), this is the fixed maximum allowed. Behavior is undefined when more stack is used than the reserved size on systems where stacks are not able to grow. The intrinsic macro ##[[KeyPgDdfbmt|__FB_MT__]]## is only automatically set from the point of usage of **""ThreadCreate""** onward. **Note:** **""-""** The ##//userdata//## parameter can be unused in the body of the ##myThread## sub, but declaring it as an ##Any Ptr## parameter is always mandatory in the header. In this case, the corresponding ##//param//## parameter can then be omitted when calling **""ThreadCreate""**, or else a needless argument can still be passed ('0' is commonly used because this value is directly compatible with any pointer). See the 2nd and 3rd example. **""-""** In the case where data must be passed to ##myThread##, the Any Ptr ##//param//## can be used to reference them, usually requiring a type conversion (implicit or explicit) into ##Any Ptr## before passing it to **""ThreadCreate""**, and a reverse type conversion from ##Any Ptr## in the body of ##myThread## before using it. See the 1st example. {{fbdoc item="ex"}} {{fbdoc item="filename" value="examples/manual/threads/threads1.bas"}}%%(freebasic) '' Threading synchronization using Mutexes '' If you comment out the lines containing "MutexLock" and "MutexUnlock", '' the threads will not be in sync and some of the data may be printed '' out of place. Const MAX_THREADS = 10 Dim Shared As Any Ptr ttylock '' Teletype unfurls some text across the screen at a given location Sub teletype( ByRef text As String, ByVal x As Long, ByVal y As Long ) '' '' This MutexLock makes simultaneously running threads wait for each '' other, so only one at a time can continue and print output. '' Otherwise, their Locates would interfere, since there is only one '' cursor. '' '' It's impossible to predict the order in which threads will arrive '' here and which one will be the first to acquire the lock thus '' causing the rest to wait. '' MutexLock ttylock For i As Integer = 0 To (Len(text) - 1) Locate x, y + i Print Chr(text[i]) Sleep 25, 1 Next '' MutexUnlock releases the lock and lets other threads acquire it. 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 '' Create a mutex to syncronize the threads ttylock = MutexCreate() '' Create child threads 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 '' This is the main thread. Now wait until all child threads have finished. 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) %% {{fbdoc item="filename" value="examples/manual/threads/threads2.bas"}}%%(freebasic) 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 %% {{fbdoc item="filename" value="examples/manual/threads/threads3.bas"}}%%(freebasic) '' 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 %% {{fbdoc item="lang"}} - Threading is not allowed in the //[[CompilerOptlang|-lang qb]]// dialect. {{fbdoc item="target"}} - **""Threadcreate""** is not available with the DOS version / target of ""FreeBASIC"", because multithreading is not supported by DOS kernel nor the used extender. - In Linux the threads are always started in the order they are created, this can't be assumed in ""Win32"". It's an OS, not a ""FreeBASIC"" issue. {{fbdoc item="diff"}} - New to ""FreeBASIC"" {{fbdoc item="see"}} - ##[[KeyPgThreadSelf|ThreadSelf]]## - ##[[KeyPgThreadWait|ThreadWait]]## - ##[[KeyPgThreadDetach|ThreadDetach]]## - ##[[KeyPgMutexCreate|Mutexcreate]]## - ##[[KeyPgMutexLock|Mutexlock]]## - ##[[KeyPgMutexUnlock|Mutexunlock]]## - ##[[KeyPgMutexDestroy|Mutexdestroy]]## - ##[[KeyPgOpProcptr|Operator ProcPtr (Procedure pointer and vtable index)]]## {{fbdoc item="back" value="CatPgThreading|Threading Support Functions"}}