Запускает процедуру, определенную пользователем, в отдельном выполняемом
потоке
Синтаксис
Использование
result = ThreadCreate ( procptr [, [ param ] [, stack_size ] ] )
Параметры
procptr
Указатель на
Sub
предназначен для работы потока. Процедура должна иметь следующую сигнатуру
(те же параметры, те же вызовы), совместимымую с
procptr:
Declare Sub myThread ( ByVal userdata As Any Ptr )
userdata
Параметр
Any Ptr - параметр
Sub
, предназначен для работы потока. FreeBASIC ожидает, что этот параметр
должен присутствовать, он не должен быть опущен!
param
Any Ptr аргумент, который будет передаваться в
потоке
Sub , на который указывает
procptr
через свой параметр
userdata. Например, это может быть указатель на
структуру или массив, содержащий различную информацию для потока. Если
param
не используется,
0 (нуль) будет передан параметру для
пользовательских данных в потоке.
stack_size
Дополнительное количество байтов зарезервированных для
стека этого потока.
Возвращаемое значение
Threadcreate возвращает Any Ptr дескриптор созданного потока,
или нулевой указатель (0) в случае неудачи.
Описание
Процедура, на которую указывает
procptr запускается как поток. Ей
будет передано содержание
param, или 0 (нуль) если не указано, в ее
параметр
userdata.
Процедура, которая была запущена как поток, будет выполняться параллельно с
основной частью программы. В операционной системе это достигается путем
передачи выполнения ее другому процессору, если он существует, или чередуя
выполнения потоков на одном процессоре. Нет гарантии о порядке, в котором
различные потоки выполняются, и нет никаких предположений о порядке, в
котором несколько создаваемых потоков фактически начинают выполнение.
Перед закрытием программы следует ждать окончания всех запущенных потоков с
помощью
ThreadWait. Кроме того,
если в этом нет необходимости, можно спокойно дожидаться окончания
выполнения потока с помощью
Threaddetach . Однако, если
программа выходит в то время как некоторые потоки все еще активны, эти
потоки будут прерваны системой. Для каждого созданного потока, программа
должна вызвать либо
ThreadWait
либо
Threaddetach для того, чтобы системные ресурсы, связанные с
дескрипторами потоков освобождались. В противном случае, могут быть утечки
памяти или системных ресурсов.
Из-за характера потоков нельзя сделать никаких предположений о порядке
выполнения. Для обмена данными между несколькими потоками, включая поток и
основную частью программы, необходимо использовать мьютексы. Эти блокировки
взаимного исключения могут «принадлежать» одному потоку при выполнении
критической работы, заставляя другие потоки ожидать своей очереди. См.
MutexCreate,
MutexLock,
MutexUnlock,
MutexDestroy.
stack_size может использоваться для изменения размера стека
потока от системного по умолчанию. Это может быть полезно, когда программа
требует большой стек, например из-за многоуровневой рекурсии процедуры или
при распределении огромных строк/массивов в стеке. На некоторых системах
(Linux) стек автоматически правит
stack_size , если
требуется больше места; на других (Win32), это фиксируется как максимально
допустимое. Поведение не определяется, когда используется больший размер
стека, чем зарезервированный для системы, в которой стек не может быть
увеличен.
Пример
'' Потоковая синхронизация с использованием мьютексов
'' Если вы закомментируйте строки, содержащие «MutexLock» и «MutexUnlock»,
'' потоки не будут синхронизированы, и некоторые из данных могут быть напечатаны
'' неуместно.
Const MAX_THREADS = 10
Dim Shared As Any Ptr ttylock
'' Телетайп разворачивает текст по экрану в определенном
месте
Sub teletype( ByRef text As String, ByVal x As Integer, ByVal y As Integer )
''
'' MutexLock создает ожидание
одновременно запущенных потоков,
'' так что только один за раз может продолжаться и выводить печать.
'' В противном случае, потоки начнут вмешиваться в
работу друг друга и портить,
''
так как существует только
один курсор.
''
'' Невозможно предсказать
порядок, в котором здесь выполняются потоки
'' и какой из них будет первым для
получения блокировки
'' и заставляя остальных ждать.
''
MutexLock ttylock
For i As Integer = 0 To (Len(text) - 1)
Locate x, y + i
Print Chr(text[i])
Sleep 25
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
'' После завершения очистка
MutexDestroy(ttylock)
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)
'' Работа (другой поток)
print_dots("*")
End Sub
Randomize(Timer())
Print " main thread: ."
Print "other thread: *"
'' Запускаем другой поток
Dim As Any Ptr thread = ThreadCreate(@mythread, 0)
'' Работа (основной поток)
print_dots(".")
'' Дожидаемся завершения другого
потока, при необходимости
ThreadWait(thread)
Print
Sleep
'' Пример многопоточности с использованием мьютексов
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
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
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
Различия диалектов
- Многопоточность не допускается в диалекте -lang qb.
Различия платформ
- Threadcreate не доступна в версии DOS FreeBASIC, потому что
многопоточность не поддерживается ядром DOS.
- В Linux потоки всегда запускаются в том порядке, котором они были созданы ,
это нельзя предположить (угадать) в Win32. Это вопрос операционных систем, а не
FreeBASIC
Отличия от QB
См. также