Problem mit Threads
Verfasst: 06.03.2016 16:52
Hallo!
Ich habe hier folgenden Code:
ThreadX() sind die aufgerufenen Threads
DistrX() sind die verteilenden Prozeduren
In der LinkedList werden in \Thread der aufgerufene Thread vermerkt
und in \Status der "Bearbeitungsstand" der aktuelle Zeile, wobei
0=nicht bearbeiten, 1=soll bearbeitet werden und -1=ist bearbeitet
bedeutete.
Es sollen 3 Threads die Liste nacheinander "abarbeiten".
Mit nur einem Thread funktionierte es ohne Probleme:
in der Procedure Start() die aufrufe Distr2() und Distr3() auskommentieren:
alle Einträge Rows()Status werden auf -1 gesetzt.
Kommen weitere Threads hinzu, werden diese auch aktiviert und durch-
laufen, aber nach etwa der 11. Zeile wird in der Liste Rows()\Status die
bearbeitete Zeile nicht mehr als bearbeitet (-1) markiert.
Daß die Threads gestartet wurden, wird in Rows()\Thread vermerkt.
Wie kann das sein?
Irgendwo muß ich hier doch einen Denkfehler gemacht haben.
Ich habe hier folgenden Code:
ThreadX() sind die aufgerufenen Threads
DistrX() sind die verteilenden Prozeduren
In der LinkedList werden in \Thread der aufgerufene Thread vermerkt
und in \Status der "Bearbeitungsstand" der aktuelle Zeile, wobei
0=nicht bearbeiten, 1=soll bearbeitet werden und -1=ist bearbeitet
bedeutete.
Code: Alles auswählen
#TestMutex=#False
CompilerIf #TestMutex
Global Mutex=CreateMutex()
CompilerEndIf
Structure Daten
Thread.i
Status.i
Pos.i
Text.s
EndStructure
Enumeration #PB_Event_FirstCustomValue
#myEvent1
#myEvent2
#myEvent3
EndEnumeration
Global NewList Rows.Daten()
Procedure Thread1(*P)
Static Thread1
Thread1+1
Debug "Start Thread1 ["+Thread1+"]"
Delay(Random(2000)); Payload
PostEvent(#myEvent1)
Debug "Thread1 ["+Thread1+"] PostEvent myEvent1"
EndProcedure
Procedure Thread2(*P)
Static Thread2
Thread2+1
Debug #TAB$+#TAB$+"Start Thread2 ["+Thread2+"]"
Delay(Random(2000)); Payload
PostEvent(#myEvent2)
Debug #TAB$+#TAB$+"Thread2 ["+Thread2+"] PostEvent myEvent2"
EndProcedure
Procedure Thread3(*P)
Static Thread3
Thread3+1
Debug #TAB$+#TAB$+#TAB$+#TAB$+"Start Thread3 ["+Thread3+"]"
Delay(Random(2000)); Payload
PostEvent(#myEvent3)
Debug #TAB$+#TAB$+#TAB$+#TAB$+"Thread3 ["+Thread3+"] PostEvent myEvent3"
EndProcedure
Procedure Distr1()
Static Distr1
Distr1+1
Debug "Enter Distr1("+Distr1+")"
Anz=CountGadgetItems(1)
i=0
CompilerIf #TestMutex
ULM=#True
LockMutex(Mutex)
Debug "Mutex locked 1"
CompilerEndIf
Repeat
ChangeCurrentElement(Rows(), GetGadgetItemData(1, i))
If Rows()\Status=1; ist selektiert
If Rows()\Thread=1; Thread 1
Rows()\Status=-1:Debug "Thread1: mark finished "+i
EndIf
Break
EndIf
i+1
Until i=Anz
i=0
Repeat
ChangeCurrentElement(Rows(), GetGadgetItemData(1, i))
If Rows()\Status=1
If Rows()\Thread=0
Rows()\Thread=1:Debug "Thread1: load line "+i
*P=GetGadgetItemData(1, i)
CompilerIf #TestMutex
UnlockMutex(Mutex)
ULM=#False
Debug "Mutex unlocked 1"
CompilerEndIf
CreateThread(@Thread1(), *P)
Break
EndIf
EndIf
i+1
Until i=Anz
CompilerIf #TestMutex
If ULM=#True
UnlockMutex(Mutex)
ULM=#False
Debug "Mutex unlocked 1 (Anz=i)"
EndIf
CompilerEndIf
ForEach Rows()
St.s+"["+Rows()\Status+"]"
Th.s+"["+Rows()\Thread+"]"
Next
Debug St
Debug Th
Debug "Leave Distr1("+Distr1+")"
EndProcedure
Procedure Distr2()
Static Distr2
Distr2+1
Debug #TAB$+#TAB$+"Enter Distr2("+Distr2+")"
Anz=CountGadgetItems(1)
i=0
CompilerIf #TestMutex
ULM=#True
LockMutex(Mutex)
Debug #TAB$+#TAB$+"Mutex locked 2"
CompilerEndIf
Repeat
ChangeCurrentElement(Rows(), GetGadgetItemData(1, i))
If Rows()\Status=1; ist selektiert
If Rows()\Thread=2; Thread 1
Rows()\Status=-1:Debug #TAB$+#TAB$+"Thread2: mark finished "+i
EndIf
Break
EndIf
i+1
Until i=Anz
i=0
Repeat
ChangeCurrentElement(Rows(), GetGadgetItemData(1, i))
If Rows()\Status=1
If Rows()\Thread=0
Rows()\Thread=2:Debug #TAB$+#TAB$+"Thread2: load line "+i
*P=GetGadgetItemData(1, i)
CompilerIf #TestMutex
UnlockMutex(Mutex)
ULM=#False
Debug #TAB$+#TAB$+"Mutex unlocked 2"
CompilerEndIf
CreateThread(@Thread2(), *P)
Break
EndIf
EndIf
i+1
Until i=Anz
CompilerIf #TestMutex
If ULM=#True
UnlockMutex(Mutex)
Debug #TAB$+#TAB$+"Mutex unlocked 2 (Anz=i)"
EndIf
CompilerEndIf
ForEach Rows()
St.s+"["+Rows()\Status+"]"
Th.s+"["+Rows()\Thread+"]"
Next
Debug St
Debug Th
Debug #TAB$+#TAB$+"Leave Distr2("+Distr2+")"
EndProcedure
Procedure Distr3()
Static Distr3
Distr3+1
Debug #TAB$+#TAB$+#TAB$+#TAB$+"Enter Distr3("+Distr3+")"
Anz=CountGadgetItems(1)
i=0
CompilerIf #TestMutex
ULM=#True
LockMutex(Mutex)
Debug #TAB$+#TAB$+#TAB$+#TAB$+"Mutex locked 3"
CompilerEndIf
Repeat
ChangeCurrentElement(Rows(), GetGadgetItemData(1, i))
If Rows()\Status=1; ist selektiert
If Rows()\Thread=3; Thread 1
Rows()\Status=-1:Debug #TAB$+#TAB$+#TAB$+#TAB$+"Thread3: mark finished "+i
EndIf
Break
EndIf
i+1
Until i=Anz
i=0
Repeat
ChangeCurrentElement(Rows(), GetGadgetItemData(1, i))
If Rows()\Status=1
If Rows()\Thread=0
Rows()\Thread=3:Debug #TAB$+#TAB$+#TAB$+#TAB$+"Thread3: load line "+i
CompilerIf #TestMutex
UnlockMutex(Mutex)
ULM=#False
Debug #TAB$+#TAB$+#TAB$+#TAB$+"Mutex unlocked 3"
CompilerEndIf
*P=GetGadgetItemData(1, i)
CreateThread(@Thread3(), *P)
Break
EndIf
EndIf
i+1
Until i=Anz
CompilerIf #TestMutex
If ULM=#True
UnlockMutex(Mutex)
Debug #TAB$+#TAB$+#TAB$+#TAB$+"Mutex unlocked 3 (Anz=i)"
EndIf
CompilerEndIf
ForEach Rows()
St.s+"["+Rows()\Status+"]"
Th.s+"["+Rows()\Thread+"]"
Next
Debug St
Debug Th
Debug #TAB$+#TAB$+#TAB$+#TAB$+"Leave Distr3("+Distr3+")"
EndProcedure
Procedure Start()
Debug "Enter Start()"
Anz=CountGadgetItems(1)
Repeat
If GetGadgetItemState(1, i)&#PB_ListIcon_Checked
ChangeCurrentElement(Rows(), GetGadgetItemData(1, i))
Rows()\Status=1
count+1
EndIf
St.s+"["+Rows()\Status+"]"
i+1
Until i=Anz
Debug count
Debug St
Debug "---------------"
Distr1()
Distr2()
Distr3()
Debug "Leave Start()"
EndProcedure
Procedure FillList(Anz)
For i = 1 To Anz
AddGadgetItem(1, -1, RSet(Str(i), 4, "0")+Chr(10)+"Row "+Str(i))
*P=AddElement(Rows())
SetGadgetItemState(1, i-1, #PB_ListIcon_Checked)
Rows()\Text="Col "+Str(i)
Rows()\Pos=i
SetGadgetItemData(1, i-1, *P)
Next
EndProcedure
OpenWindow(1, 10, 10 ,640, 480, "")
ListIconGadget(1, 0, 0, WindowWidth(1), WindowHeight(1)-30, "Col 1", 120, #PB_ListIcon_CheckBoxes)
AddGadgetColumn(1, 1, "Col 2", 120)
AddGadgetColumn(1, 2, "Col 3", 120)
AddGadgetColumn(1, 3, "Col 4", 120)
ButtonGadget(11, 10, GadgetHeight(1)+2, 64, 24, "Start")
BindGadgetEvent(11, @Start())
BindEvent(#myEvent1, @Distr1())
BindEvent(#myEvent2, @Distr2())
BindEvent(#myEvent3, @Distr3())
FillList(20)
quit=#False
Repeat
Event=WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
quit=#True
EndSelect
Until quit=#True
Mit nur einem Thread funktionierte es ohne Probleme:
in der Procedure Start() die aufrufe Distr2() und Distr3() auskommentieren:
alle Einträge Rows()Status werden auf -1 gesetzt.
Kommen weitere Threads hinzu, werden diese auch aktiviert und durch-
laufen, aber nach etwa der 11. Zeile wird in der Liste Rows()\Status die
bearbeitete Zeile nicht mehr als bearbeitet (-1) markiert.
Daß die Threads gestartet wurden, wird in Rows()\Thread vermerkt.
Wie kann das sein?
Irgendwo muß ich hier doch einen Denkfehler gemacht haben.