[Hilfe] Threads wie?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

[Hilfe] Threads wie?

Beitrag von Mijikai »

Leider kann ich immer noch nicht mit Threads umgehen.

Folgendes will ich umsetzen:
- Funktion erstellt einen Thread und übergibt eine Struktur
- Thread fängt an zu Arbeiten und updated Informationen in der Struktur
- Eine andere Funktion kann Informationen aus der Struktur lesen während der Thread noch läuft
- Thread kann jederzeit abgebrochen werden

Wie kann ich das umsetzten?
(Semaphores, Mutex ...)
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: [Hilfe] Threads wie?

Beitrag von RSBasic »

In der PB-Hilfe unter CreateSemaphore() findest du unten ein Beispielcode. Damit wird sichergestellt, dass die globale NewList immer von einer Prozedur zugegriffen oder geändert wird.
Den Code kannst du übernehmen. Der einzige Unterschied ist nur, dass du keine NewList verwendest, sondern eine Struktur.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: [Hilfe] Threads wie?

Beitrag von Mijikai »

Danke @RSBasic leider versteh ich nur Bahnhof.

Was ich versuche zu realisieren:

Code: Alles auswählen

Structure TASK_STRUCT
  Thread.i
  Semaphore.i
  Count.i
  State.i
EndStructure

Procedure.i Task(*Task.TASK_STRUCT)
  With *Task
    While Not \Count = 100
      Delay(2000)
      \Count + 1;<- Wie schützen? Damit die GatTaskState() Funktion nicht dazwischen funkt!?
    Wend  
    \State = #True;<- Task fertig! Wie schützen?
  EndWith
EndProcedure

Procedure.i CreateTask();<- Gibt eine neuen Task zurück (Struktur)
  Protected *Task.TASK_STRUCT
  Protected Thread.i
  *Task = AllocateStructure(TASK_STRUCT)
  If *Task
    With *Task
      \Semaphore = CreateSemaphore()
      If \Semaphore
        \Thread = CreateThread(@Task(),*Task)
        If \Thread
          ProcedureReturn *Task
        Else
          FreeSemaphore(\Semaphore)
          FreeStructure(*Task)
        EndIf 
      EndIf
    EndWith
    FreeStructure(*Task)
  EndIf 
EndProcedure

Procedure.i GetTaskCount(*Task.TASK_STRUCT)
  Debug *Task\Count;<- Wie auf den Thread korrekt zugreifen?
EndProcedure

Procedure.i GetTaskState(*Task.TASK_STRUCT)
  Debug *Task\State;<- Wie auf den Thread korrekt zugreifen?
EndProcedure

Procedure.i EndTask(*Task.TASK_STRUCT)
  Protected Count.i
  If *Task\State = #True;<- Wie auf den Thread korrekt zugreifen?
    Count = *Task\Count
    FreeSemaphore(*Task\Semaphore)
    FreeStructure(*Task)
    ProcedureReturn Count
  Else
    ;-> Wie kann ich den Thread abbrechen und beenden wenn er noch läuft?
  EndIf 
EndProcedure

Global Task.i
Global Exit.i

Task = CreateTask()
If Task
  Repeat
    GetTaskCount(Task)
    If GetTaskState(Task)
      EndTask(Task)
      Exit = #True
    EndIf 
  Until Exit
EndIf 
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

Re: [Hilfe] Threads wie?

Beitrag von #NULL »

- Semaphoren sind eher da um zwischen Threads zu steuern. Verwende lieber einen Mutex um Daten zu schützen.
- Ein zusätzliches Feld Running ermöglicht den Thread von außen zu beenden.
- zwischen jedem Count+1 wird auch anderen Threads eine Zugriffsmöglichkeit gegeben, deswegen ist das While jetzt nur ein If und die Schleife ist außen drum, der Mutex wird pro Schleifendurchgang gelockt, und noch ein Delay(1) damit main zwischendurch eine Chance zum Zugriff hat.
- dein FreeStructure() in CreateTask() wäre übrigens doppelt aufgerufen worden.
- wie EndTask() aussehen soll bin ich mir nicht sicher. Ich würde das wohl eher aufteilen in WaitTask(), EndTask(), FreeTask() o.d.g., so dass man z.b. den Task beenden/abbrechen, danach aber immer noch state/count abfragen, und dann den Speicher separat freigeben kann.

Code: Alles auswählen

Structure TASK_STRUCT
  Thread.i
  Mutex.i
  Count.i
  State.i
  Runnning.i
EndStructure

Declare.i GetTaskRunning(*Task.TASK_STRUCT)

Procedure.i Task(*Task.TASK_STRUCT)
  Protected taskRunning
  taskRunning = GetTaskRunning(*Task)
  While taskRunning
    LockMutex(*Task\Mutex)
    With *Task
      If Not \Count = 10
        Debug "+"
        Delay(100)
        \Count + 1
      Else
        \State = #True
        \Runnning = #False
      EndIf
    EndWith
    UnlockMutex(*Task\Mutex)
    Delay(1)
    taskRunning = GetTaskRunning(*Task)
  Wend
EndProcedure

Procedure.i CreateTask()
  Protected *Task.TASK_STRUCT
  Protected Thread.i
  *Task = AllocateStructure(TASK_STRUCT)
  If *Task
    With *Task
      \Mutex = CreateMutex()
      If \Mutex
        \Runnning = #True
        \Thread = CreateThread(@Task(),*Task)
        If \Thread
          ProcedureReturn *Task
        Else
          FreeMutex(\Mutex)
        EndIf
      EndIf
    EndWith
    FreeStructure(*Task)
  EndIf
EndProcedure

Procedure.i GetTaskCount(*Task.TASK_STRUCT)
  Protected taskCount
  LockMutex(*Task\Mutex)
  taskCount = *Task\Count
  UnlockMutex(*Task\Mutex)
  ProcedureReturn taskCount
EndProcedure

Procedure.i GetTaskState(*Task.TASK_STRUCT)
  Protected taskState
  LockMutex(*Task\Mutex)
  taskState = *Task\State
  UnlockMutex(*Task\Mutex)
  ProcedureReturn taskState
EndProcedure

Procedure.i GetTaskRunning(*Task.TASK_STRUCT)
  Protected taskRunning
  LockMutex(*Task\Mutex)
  taskRunning = *Task\Runnning
  UnlockMutex(*Task\Mutex)
  ProcedureReturn taskRunning
EndProcedure

Procedure.i EndTask(*Task.TASK_STRUCT)
  Protected Count.i
  
  If GetTaskState(*Task) = #True
    Count = GetTaskCount(*Task)
  Else
    Count = -1 ; (z.b.)
  EndIf
  
  LockMutex(*Task\Mutex)
  *Task\Runnning = #False
  UnlockMutex(*Task\Mutex)
  WaitThread(*Task\Thread)
  
  FreeMutex(*Task\Mutex)
  FreeStructure(*Task)
  
  ProcedureReturn Count
EndProcedure

Global Task.i
Global Exit.i

Task = CreateTask()
If Task
  Repeat
    Debug "main: " + GetTaskCount(Task)
    If GetTaskState(Task)
      EndTask(Task)
      Debug "main: exit"
      Exit = #True
    EndIf
    Delay(1)
  Until Exit
EndIf 
Zuletzt geändert von #NULL am 17.09.2018 14:03, insgesamt 1-mal geändert.
my pb stuff..
Bild..jedenfalls war das mal so.
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: [Hilfe] Threads wie?

Beitrag von Mijikai »

#NULL hat geschrieben:- Semaphoren sind eher da um zwischen Threads zu steuern. Verwende lieber einen Mutex um Daten zu schützen.
- Ein zusätzliches Feld Running ermöglicht den Thread von außen zu beenden.
- zwischen jedem Count+1 wird auch anderen Threads eine Zugriffsmöglichkeit gegeben, deswegen ist das While jetzt nur ein If und die Schleife ist außen drum, der Mutex wird pro Schleifendurchgang gelockt, und noch ein Delay(1) damit main zwischendurch eine Chance zum Zugriff hat.
- dein FreeStructure() in CreateTask() wäre übrigens doppelt aufgerufen worden.
- wie EndTask() aussehen soll bin ich mir nicht sicher. Ich würde das wohl eher aufteilen in WaitTask(), EndTask(), FreeTask() o.d.g., so dass man z.b. den Task beenden/abbrechen, danach aber immer noch state/count abfragen, und dann den Speicher separat freigeben kann.
...
Vielen Dank hat mir geholfen :)
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

Re: [Hilfe] Threads wie?

Beitrag von #NULL »

Ich habe noch etwas korrigiert in EndTask() :

Code: Alles auswählen

*Task\Runnning = #False
War vorher ... = #True, was keinen Sinn macht, der Thread soll ja zum Abbruch bewegt werden anstatt stur fertig zu zählen.
my pb stuff..
Bild..jedenfalls war das mal so.
Antworten