[BCB] Multithreaded GUI hangt soms even *

Pagina: 1
Acties:
  • 134 views sinds 30-01-2008
  • Reageer

  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Ik ben al een poos bezig met C++ Builder 6.0. Ik weet inmiddels wel wat van het programma en het programmeren af.
Ik ben al een poosje bezig geweest met het maken van een multi-threaded programma. Ik kan b.v. 2 statusbars onafhankelijk van elkaar laten lopen, en ook ben ik bekend met Critical Section.

Ik ben bezig met een programma wat data verstuurd via de SCSI bus. Verder niet echt belangrijk, maar in combinatie met mijn mutli-threaded programma wil het niet echt lukken.
Ik kan 2 apparaten tegelijk aansturen(data) maar het probleem is, dat mijn grafische interface enorm hangt dan.
Mijn vraag is eigenlijk simpel > Hoe kan ik ervoor zorgen dat ik b.v. 7 threads heb lopen (7 apparaten tegelijk datasturen / lezen) en ook mijn grafische interface goed kan gebruiken (menubalk e.d. gebruiken).
Ik maak ik mijn programma veelvoudig gebruik van events en daarbij behorende waitforsingleobject om te controleren of een scsi commando is gelukt.
Mocht er code vereist zijn dan hoor ik dat graag O-)

offtopic:
Ik hoop niet dat er geflamed wordt m.b.t kennis niveau. Ik doe mijn best om alles goed te leren, maar ik weet ook nog niet alles :P. Ik heb deze post ook op een ander forum staan, maar hoop op deze manier nog meer info te krijgen.

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • dawuss
  • Registratie: Maart 2001
  • Laatst online: 01-02 20:46

dawuss

gadgeteer

Wat heel belangrijk is voor deze vraag: Welke libraries gebruik je? pthreads?
en waarmee stuur je je grafische interface aan? En onder welk besturinsgssysteem?

micheljansen.org
Fulltime Verslaafde Commandline Fetisjist ©


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Waarom maak je niet een event afhandelende thread voor je gui? (als die er al niet is) Je maakt een queue waarin alle threads events (updates) mag posten. Je eventqueue heeft 1 thread die events verwerkt en ligt te maffen met bv een semafoor. Scheelt je een hele lading concurrency meuk.

En verder is het verboden om dure acties uit te voeren op de eventdispatching thread omdat andere events niet verwerkt worden (het gevolg is een non-responsive gui)

[ Voor 29% gewijzigd door Alarmnummer op 10-01-2005 12:38 ]


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Sorry. Was ik idd vergeten te vertellen: Ik gebruik Borland C++ Builder 6.0 onder Windows XP Pro. Ik maak gebruik van TThread onder C++.
In mijn "mainprogramma" heb ik de volgende code staan:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
for (byHaId = 0; byHaId < MAX_HA_ID; byHaId++)                  // Scan loop for host adapters 
{ 

  for (byTarget = 0; byTarget < MAX_TARGET_ID; byTarget++)      // Scan loop for targets 
   { 
    SRB_GDEVBlock srbGDEVBlock; 
    memset(&srbGDEVBlock, 0, sizeof(SRB_GDEVBlock));            // Sets memory for DDEVBlock to zero 
    srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;                     // Sets Command for Get Device Type 
    srbGDEVBlock.SRB_HaId = byHaId;                             // Sets the host adapter ID 
    srbGDEVBlock.SRB_Target = byTarget;                         // Sets the target ID 

    pfnSendASPI32Command((LPSRB)&srbGDEVBlock);                 // Sends the command to the ASPI layer 
    if (srbGDEVBlock.SRB_Status == SS_COMP)                     // Check if of command is completed 
     { 
      if (srbGDEVBlock.SRB_DeviceType == DTYPE_SEQD)            // Check for a sequential access device 
       { 
        AnsiString DevScan; 
        DevScan = String("Adapter: ") + byHaId + String(" Target: ") + byTarget + String(" A DLT is FOUND"); 
        char DevScanPRTF[50]; 
        sprintf(DevScanPRTF,"%s",DevScan); 
        MessageBox(NULL,DevScanPRTF,"Device",MB_OK);            // Message on what adapter and target a device is found 
        Tdata = new myData(false,byHaId,byTarget); 
       } 
      else 
       { 
        MessageBox(NULL,"Geen Sequential Acces Device Gevonden","Scan",MB_OK);   // Nothing found 
        return;                                                 // Return to main program 
       } 
     } 
   }


Hier wordt aan de hand van het Target en Hostadapter ID een thread opgestart als er een Sequential Acces Device wordt gedetecteerd. In mijn main programma start ik dus een nieuwe Thread. In deze thread worden verder de acties uitgevoerd. Verder wordt in mijn hoofdprogramma niet omgegeken naar deze threads. De threads zorgen voor de verdere afhandeling wat betreft data. Wel gebruik ik veel waitforsingleobject en event handlers.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SRB_ExecSCSICmd srbExec;                                        // Changes the "name" of SRB_ExecSCSICmd to srbExec
heventSRB = CreateEvent (NULL, TRUE, FALSE, NULL);              // Creat a Event for SRB_ExecSCSICmd

memset(&srbExec, 0, sizeof(SRB_ExecSCSICmd));                   // Sets memory for ExecSCSICmd to zero
  srbExec.SRB_Cmd        = SC_EXEC_SCSI_CMD;                    // SC_EXEC_SCSI_CMD value
  srbExec.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;       // Necessary for the event handle
  srbExec.SRB_HaId       = byHostAdapTerID;                     // Host adapter ID = 0
  srbExec.SRB_Target     = byTarGetID;                          // Target ID = 2
  srbExec.SRB_Lun        = 0;                                   // Lun = 0
  srbExec.SRB_BufLen     = 32;                                  // Define length of data (in bytes) that
                                                                // The device send back to the computer
  srbExec.SRB_BufPointer = byInquiry;                           // Set the pointer to the begin adress of "byInquiry" so that the information the device return comes in variable "byInquiry"
  srbExec.SRB_SenseLen   = SENSE_LEN;                           // Define number of sense bytes used at the end off data bytes
  srbExec.SRB_CDBLen     = 6;                                   // The srbExec.SRB_CDBLen is 6 bytes
  srbExec.SRB_PostProc   = (LPVOID)heventSRB;                   //
  srbExec.CDBByte[0]     = 0x12;                                // Send ASPI Command for vendor ID and Type Number
  srbExec.CDBByte[4]     = 32;                                  // The number of return data = 32
  ResetEvent (heventSRB);                                       // Reset the event handle
  dwASPIStatus = pfnSendASPI32Command( (LPSRB)&srbExec);        // Send ASPI command
  if(dwASPIStatus == SS_PENDING)                                // Check if device is busy
   {
    WaitForSingleObject( heventSRB,INFINITE);                   // Wait for device status is "ready"
   }

Dat gebeurd veelal in de thread. Verder vraag ik dus geen data op uit de Thread in het mainprogramma.. Ik vindt het daarom raar waarom mijn GUI niet normaal reageerd.

[ Voor 3% gewijzigd door IJnte op 10-01-2005 12:53 ]

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • yade
  • Registratie: Mei 2002
  • Laatst online: 25-11-2025
Hoeveel CPU tijd gebruikt je programma?

Misschien heb je ergens een lus die 100% cpu tijd gebruikt.

  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
yade schreef op maandag 10 januari 2005 @ 13:42:
Hoeveel CPU tijd gebruikt je programma?

Misschien heb je ergens een lus die 100% cpu tijd gebruikt.
Neej zeker niet. Bij mij taskmanager (MSI Mega PC met P4 2.4ghz) blijft het cpu gebruik zo rond de 20% schommelen als ik 2 apparaten tegelijk aanstuur.

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

In principe mag je geen hangers krijgen als je geen waits in the main thread hebt. Gebruik je echt nergens de TThread.Synchronize calls of WaitForSingleObject in the main thread? :?

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Ik heb het net even gecontroleerd, maar er zitten echt geen waits (loops oid) in mijn main programma(gewoon TForm1) of synchronize functies in mijn hoofdprogramma. Moet ik anders even de code opsturen misschien :? :? :?

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Wat je het beste kunt doen: ga lekker debuggen in BCB en ram op de 'pauze' knop zodra de GUI hangt. Zie je direct aan de call stack waar ie zit :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
O-) Even het schoolnetwerk omzeilt :*) .
Afbeeldingslocatie: http://62.234.163.86/bcbfout.jpg
Dat is de fout die ik krijg. Hij blijft dus echt hangen bij WaitForSingleObject, en die staat echt alleen in een TThread ;(

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

In het 'Debug' menu bij 'Windows' kun je ook 'Threads' overview selecteren, even dubbelklikken op de goeie thread om de call stack van de goeie thread te zien ;)

Professionele website nodig?


  • The End
  • Registratie: Maart 2000
  • Laatst online: 20:11

The End

!Beginning

IJnte schreef op maandag 10 januari 2005 @ 15:12:
Ik heb het net even gecontroleerd, maar er zitten echt geen waits (loops oid) in mijn main programma(gewoon TForm1) of synchronize functies in mijn hoofdprogramma. Moet ik anders even de code opsturen misschien :? :? :?
Haalt de main thread ook geen data op van die andere threads, waar crititical sections gebruikt worden?

Het lijkt uit je verhaal nu net alsof die threads gestart worden en daarna nooit meer iets aan de gui terugmelden?

  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
curry684 schreef op maandag 10 januari 2005 @ 15:42:
In het 'Debug' menu bij 'Windows' kun je ook 'Threads' overview selecteren, even dubbelklikken op de goeie thread om de call stack van de goeie thread te zien ;)
Ik krijg dan het volgende:
Afbeeldingslocatie: http://62.234.163.86/bcbfout1.jpg
Ik snap daar echt nix van (heb wel een beetje assembly gedaan, maar dat vat ik niet iig).
Verder ziet mijn programma er zo uit:
Afbeeldingslocatie: http://62.234.163.86/bcbprogramma.jpg
Zodra als ik op de knop "Duurtest" druk dan komt de bovenstaande code in werking. Hij scant dan de SCSI bus op apparaten, en als er 1 gevonden wordt dan wordt er een nieuwe thread gestart. Deze thread doet nix anders dan data schrijven, terugspoelen, en daarna data lezen. In de GUI wordt de statusbalk alleen aangestuurd. Meer gebeurdt er niet in die thread.

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

IJnte schreef op maandag 10 januari 2005 @ 16:09:
[...]

Ik krijg dan het volgende:
[afbeelding]
Ik snap daar echt nix van (heb wel een beetje assembly gedaan, maar dat vat ik niet iig).
Het feit dat ie ergens in assembly steekt is niet boeiend, het gaat erom dat je in de Call Stack ziet welke methodes in jouw programma hij ergens in hangt :)
Zodra als ik op de knop "Duurtest" druk dan komt de bovenstaande code in werking. Hij scant dan de SCSI bus op apparaten, en als er 1 gevonden wordt dan wordt er een nieuwe thread gestart. Deze thread doet nix anders dan data schrijven, terugspoelen, en daarna data lezen. In de GUI wordt de statusbalk alleen aangestuurd. Meer gebeurdt er niet in die thread.
Maareuj hoe besluit je dan wanneer de progressbar vooruit geschoven moet worden? Daar zal toch enige vorm van terugkoppeling vanuit de threads in zitten? Want het zier er inderdaad zoals The End al hint uit alsof je met een klassiek stukje starvation-by-locking zit.

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
mmm dat ga ik even uitzoeken. Ik doe het als volgt:
In mijn "execute" van mijn TThread staat het volgende:"
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void __fastcall myData::Execute()
{
        //---- Place thread code here ----
FreeOnTerminate = true;
LoadASPI();
Check = false;

Synchronize(CompressOff);  // hoeft 1 x te gebeuren.

byMSB = 0x01;
byTus = 0x00;
byLSB = 0x00;
Synchronize(ModeselectBlock);

for(int p=0;p <=1000;p++)
{
Synchronize(SchrijfData);
}

Synchronize(Rewind);

for(int p=0;p<=1000;p++)
{
Synchronize(LeesData);
}


}

Hij stelt in dat het apparaat van zijn compresmode afmoet. Daarna stelt hij een parameter in voor het apparaat (blocksize). Daarna gaat het programma 1000x een block data schrijven van 64kb. Dit gaat allemaal nog goed. In Synchronize(SchrijfData) wordt de progressbar geupdate:
C++:
1
2
3
4
SRB_ExecSCSICmd srbExec;                                        // Changes the "name" of SRB_ExecSCSICmd to srbExec

Form3->ProgressBar3->Position++;
heventSRB = CreateEvent (NULL, TRUE, FALSE, NULL);              // Creat a Event handle

Wat er gebeurt is dat de positie van de progressbar wordt verhoogt met 1. Lijkt me verder niet vertragend oid :? . Bij lezen gebeurd hetzelfde. Hij hangt echt bij Synchronize(Rewind).

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

curry684 schreef op maandag 10 januari 2005 @ 14:55:
In principe mag je geen hangers krijgen als je geen waits in the main thread hebt. Gebruik je echt nergens de TThread.Synchronize calls of WaitForSingleObject in the main thread? :?
Je hele programma bestaat eruit man :X

Kijk eens voor de lol goed na wat die functie doet 8)7

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
curry684 schreef op maandag 10 januari 2005 @ 16:55:
[...]

Je hele programma bestaat eruit man :X

Kijk eens voor de lol goed na wat die functie doet 8)7
Dat is niet in mijn "main thread".... Dat is de thread die wordt opgestart om data te sturen :? Of begrijpen we elkaar verkeerd wat betreft "main thread". Als dat het geval is, kun je dan misschien uitleggen wat slim is om te doen :?

[ Voor 13% gewijzigd door IJnte op 10-01-2005 17:00 ]

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Lees nu nog eens wat die Synchronize functie doet en leg daarna eens uit waarom je 'm in godesnaam hier gebruikt :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
haha owkee. Nou ik gebruik Synchronize omdat dit volgens mij een vorm van thead save programmeren is. TThread.Synchronize is een protected procedure d8 ik zo. Daarom gebruik ik het.. Ook is het voor mij gemakkelijk om een simpele loop te maken.
Wat zou hier verkeerd aan moeten zijn :?
Ik heb overigens in zo'n synchronize code (Schrijfdata) dit staan:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
void __fastcall myData::SchrijfData()
{
if(!Check)
{
SRB_ExecSCSICmd srbExec;                                        // Changes the "name" of SRB_ExecSCSICmd to srbExec

Form3->ProgressBar3->Position++;
heventSRB = CreateEvent (NULL, TRUE, FALSE, NULL);              // Creat a Event handle

memset(&srbExec, 0, sizeof(SRB_ExecSCSICmd));                   // Sets memory for ExecSCSICmd to zero
  srbExec.SRB_Cmd        = SC_EXEC_SCSI_CMD;                    // SC_EXEC_SCSI_CMD value
  srbExec.SRB_Flags      = SRB_DIR_OUT | SRB_EVENT_NOTIFY;      // SCSI flags
  srbExec.SRB_HaId       = HostID1;                                   // Host adapter ID = 0
  srbExec.SRB_Target     = TargetID1;                                   // Target ID = 2
  srbExec.SRB_Lun        = 0;                                   // Lun = 0
  srbExec.SRB_SenseLen   = SENSE_LEN;                            // Define number of sense bytes used at the end off data bytes
  srbExec.SRB_BufLen     = 65536;                     // Define length of data (in bytes)
  srbExec.SRB_BufPointer = Form1->byPattern;                             // Variable byDataSend
  srbExec.SRB_CDBLen     = 6;                                   // The srbExec.SRB_CDBLen is 6 bytes
  srbExec.SRB_PostProc   = (LPVOID)heventSRB;                   // Post routine for event
  srbExec.CDBByte[0]     = 0x0A;                                // Send the hex code 0x0A, this is the rweind command
  srbExec.CDBByte[1]     = 1;                                   // Fixed bit = 1
  srbExec.CDBByte[2]     = 0;                                   // ammount of blocks to send to the drive  MSB
  srbExec.CDBByte[3]     = 0;                                   //    "     "  "      "   "   "   "  "      "
  srbExec.CDBByte[4]     = 1;                                   // ammount of blocks to send to the drive  LSB
  srbExec.CDBByte[5]     = 0;                                   // Reserved
  ResetEvent (heventSRB);                                       // Reset the event handle
  dwASPIStatus = pfnSendASPI32Command( (LPSRB)&srbExec);        // Sent ASPI command
  if(dwASPIStatus == SS_PENDING)                                // Check if device is busy
   {
    WaitForSingleObject( heventSRB,INFINITE);                   // Wait for device status is "ready"
   }
  if(srbExec.SRB_Status != SS_COMP)                             // Check if the ASPI command is executed succesfull
   {
    Check = true;
    MessageBox (NULL,"Write Error","Fatal error", MB_ICONERROR );                              // If not show MessageBox > "Error Data Send"
    SenseKey = srbExec.SenseArea[2];
    SenseKey = SenseKey & 15;
    ASC = srbExec.SenseArea[12];
    ASCQ = srbExec.SenseArea[13];
    SenseData(SenseKey,ASC,ASCQ);
    char Errorcode1[50];
    AnsiString ErrorCode2;
    ErrorCode2 = Form1->ErrorCode;
    sprintf(Errorcode1,"%s",ErrorCode);
    MessageBox (NULL,Errorcode1,"ErrorCode", MB_ICONERROR );
   }

}
 //} // End of Loop




}

Ben ik nou echt zo dom bezig dan :? Plz help me een beetje op weg. Zoals ik al zei is mijn kennisniveau niet super, maar ik probeer toch de eindjes aan elkaar te knopen. Ik heb btw heel erg veel info uit het Borland C++ Builder 6 Developer's Guide.

[ Voor 7% gewijzigd door IJnte op 10-01-2005 17:13 ]

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Ik zal even de online help voor je citeren:
Synchronize causes the call specified by Method to be executed using the main VCL thread, thereby avoiding multi-thread conflicts. If you are unsure whether a method call is thread-safe, call it from within the main VCL thread by passing it to the Synchronize method.
Synchronize maakt van de functie die je aanroept een zogenaamde User APC (Asynchronous Procedure Call) in de main thread. Oftewel de functie wordt 'gequeued' in de main thread context, en daar wordt ie volledig uitgevoerd alvorens de main thread z'n normale werk kan voortzetten (zoals windows messages uit de queue lezen).

Voel je het probleem al? :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
aha!! dus wat ie doet is hem eigenlijk uitvoeren in de "main thread" en daar wordt dan automatisch ook al het werk gestopt! Dus als ik data gestuurd wordt naar het apparaat via synchronize dan wordt dit werkelijk uitgevoerd als functie in de main thread. Hierdoor stopt de main thread totdat de data verstuurd is...
Zeg ik dit goed zo :?

Wat zou ik moeten veranderen om dit verschijnsel eruit te slopen. Ik neem aan dat ik synchronize niet meer moet gebruiken, maar een andere manier van een functie aanroepen :? Heeft iemand misschien hier een voorbeeld voor/van :?

offtopic:
Ik wordt nu mijn lokaal uit gekickt. Ga zo thuis even verder prutsen ;).

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 14:22

Creepy

Tactical Espionage Splatterer

Gewoon los aanroepen als die functies threadsafe zijn. Als ze dat niet zijn heb je pech en zul je ze threadsafe moeten maken.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Feitelijk gezien heb je door alles in Synchronize te frotten gewoon een single-threaded programma geschreven ja :P

Ik zie uberhaupt het nut niet van al die synchronizes... je moet die functies gewoon direct aanroepen en alleen potentieel gevaarlijke datatoegang beveiligen middels een critical section of mutex. Dan kunnen alle threads lekker voluit doorbollen, ongehinderd door wait states van de anderen, en dan kan de main thread lekker z'n message pump laten doorraggen :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Creepy schreef op maandag 10 januari 2005 @ 17:36:
Gewoon los aanroepen als die functies threadsafe zijn. Als ze dat niet zijn heb je pech en zul je ze threadsafe moeten maken.
Mmm.. ik heb het net even allemaal omgezet (synchronize eruit) en idd het werk zoals het moet werken nu :*) . Met 1 apparaat aan de SCSI bus werkt het prima, maar zodra als er 2 apparaten aanhangen (en dus 2 threads worden opgestart) krijg ik problemen. Dit zit vooral denk ik in de variabelen beveiliging. Ik heb geprobeerd met een CriticalSection de boel te beveiligen. Echter dan doet mijn programma vrij weinig. 1 Apparaat wordt dan maar aangestuurd...
Weet iemand hoe ik zeg maar beide threads (wat dus dezelfde class heeft) kan beveiligen om zo wel 2 aparaten tegelijk aan te sturen :?

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

IJnte schreef op dinsdag 11 januari 2005 @ 11:18:
[...]
Weet iemand hoe ik zeg maar beide threads (wat dus dezelfde class heeft) kan beveiligen om zo wel 2 aparaten tegelijk aan te sturen :?
Volgens mij gaat er iets fundamenteels fout.

Als jij 2 instanties van dezelfde classes hebt, hoeven ze (als ze geen data sharen) niet gesynchronized te worden. Snap je dit??

Zo lang die threads geen data sharen, hoeft er dus helemaal 0.0 gesynchronized te worden. Want ze hebben van alle velden hun eigen instantie.

[ Voor 15% gewijzigd door Alarmnummer op 11-01-2005 11:32 ]


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Alarmnummer schreef op dinsdag 11 januari 2005 @ 11:31:
[...]

Volgens mij gaat er iets fundamenteels fout.

Als jij 2 instanties van dezelfde classes hebt, hoeven ze (als ze geen data sharen) niet gesynchronized te worden. Snap je dit??

Zo lang die threads geen data sharen, hoeft er dus helemaal 0.0 gesynchronized te worden. Want ze hebben van alle velden hun eigen instantie.
Ik heb dat hele synchronize eruit gegooit. Het moeten op zichzelfstaande threads zijn, dus tussen de threads hoeft geen data geshared te worden. Alleen moet elke thread in de GUI een textbox updaten. Alleen omdat ze allemaal hezelfde doen, hebben ze allemaal dezelfde class (instanties :?).

Volgens mij werken de threads wel gelijktijdig in dezelfde functie. Als ik werk met cricital sections dan start maar 1 apparaat met het programma en het andere apparaat doet dan niks. Echt vaag :X

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

IJnte schreef op dinsdag 11 januari 2005 @ 11:51:
[...]
Ik heb dat hele synchronize eruit gegooit. Het moeten op zichzelfstaande threads zijn, dus tussen de threads hoeft geen data geshared te worden. Alleen moet elke thread in de GUI een textbox updaten. Alleen omdat ze allemaal hezelfde doen, hebben ze allemaal dezelfde class (instanties :?).
Idd
Volgens mij werken de threads wel gelijktijdig in dezelfde functie.
Ze zitten wel in dezelfde functie, maar dat wil niet zeggen dat ze de data in die functie ook sharen ;) Als jij een recursieve functie maakt (even threads buiten beschouwing laten) dan krijg jij voor iedere call toch een aparte 'ruimte' (technische termen heet het een stackframe) waarin alle variablen die in die functie staan hun eigen waarde hebben zonder dat ze last hebben van de calls ervoor en erna.
Als ik werk met cricital sections dan start maar 1 apparaat met het programma en het andere apparaat doet dan niks. Echt vaag :X
Ik probeer threads altijd te zien als mensen die een taak uitvoeren (maakt het minder abstract). Jouw werkers mogen dus onafhankelijk met de aparaten aan de slag gaan (iedere werker heeft zijn eigen boormachine). Maar als de werkers aan het einde van de dag doorgeven wat ze allemaal gedaan hebben aan een balie. Dan moet maar 1 werker tegelijk praten, anders gaat het fout. Dit is het punt dat je gaan synchronizen. Je zegt: ik ben nu bij de balie.. ramt de deur naar de balie dicht en zorgt er hiermee voor dat andere mensen niet bij de balie kunnen komen. Als je klaar bent doe je de deur weer open zodat anderen er weer inkunnen. Als jij bij de balie komt en de deur is dicht.. ga je ervoor wachten.. totdat de deur open gaat.

Ik zou eerst proberen om goed te begrijpen wat je fout doet... wat je dus neit begrijpt. En je hoeft je niet te schamen.. concurrency is gewoon extreem complex.

[ Voor 16% gewijzigd door Alarmnummer op 11-01-2005 12:53 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

IJnte schreef op dinsdag 11 januari 2005 @ 11:51:
[...]

Als ik werk met cricital sections dan start maar 1 apparaat met het programma en het andere apparaat doet dan niks. Echt vaag :X
De TCriticalSection implementatie van Borland is als singleton uitgevoerd, oftewel zodra er iemand op lockt is iedereen 'genaaid'. Beetje idioot, maar het gedrag is dus correct als je lomp lockt. Je moet alleen locken zodra je even een thread-unsafe variabele benadert, en direct unlocken zodra je daarmee klaar bent.

Sowieso is het updaten van de progressbar iets dat in de mainthread moet gebeuren om veilig de Win32 architectuur te gebruiken, dus 'even de progressbar updaten' moet je eigenlijk wel juist middels Synchronize doen :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
curry684 schreef op dinsdag 11 januari 2005 @ 12:48:
[...]

De TCriticalSection implementatie van Borland is als singleton uitgevoerd, oftewel zodra er iemand op lockt is iedereen 'genaaid'. Beetje idioot, maar het gedrag is dus correct als je lomp lockt. Je moet alleen locken zodra je even een thread-unsafe variabele benadert, en direct unlocken zodra je daarmee klaar bent.

Sowieso is het updaten van de progressbar iets dat in de mainthread moet gebeuren om veilig de Win32 architectuur te gebruiken, dus 'even de progressbar updaten' moet je eigenlijk wel juist middels Synchronize doen :)
Mmm weer wat geleerd !!! Ik ben vandaag maar eens overgestap naar het gebruik van een Mutex. Volgens het borland C++ boek:
Note:
Unlike Critical Sections, two or more processes can use the same mutex.
Ik heb ook even kort gekeken naar de Semaphore maar dat leek me niet de goede oplossing.
Even terug te komen op de Mutex. Ik heb het als volgt ge-implementeerd:
C++:
1
2
3
4
5
6
7
8
9
10
for(int p=0;p <=1000;p++)
{
  Result=WaitForSingleObject(Mutex,INFINITE);

  if(Result == WAIT_OBJECT_0)
  {
  SchrijfData();
  ReleaseMutex(Mutex);
  }
}

Zie ook even het verschil met de vorige keer. Echter dit werkt ook nog niet zoals het moet. Als dit in een loop staat zoals hierboven, en er lopen 2 threads tegelijk dan loopt ie gewoon niet 1000x door die functie heen. Heel raar al zeg ik het zelf.
Ik zal nog even kort de situatie schetsen om het voor mijzelf ook even wat duidelijker te maken:
Afbeeldingslocatie: http://home.wanadoo.nl/mhijong19/pictures/Prob1.jpg
Dat is het hoofdprogramma. Kijk heel simpel of er apparaaten aan de SCSI bus hangen, en maakt daarna een thread aan. De thread krijgt het Hostadapter + Target ID mee als variabele.
De thread moet vervolgens (heel basic) het volgende doen:
Afbeeldingslocatie: http://home.wanadoo.nl/mhijong19/pictures/Prob2.jpg
Als er 2 apparaten gevonden zijn, moeten er dus 2 threads lopen. Deze 2 threads moeten data sturen naar het apparaat met hun Host en Target ID. Koppeling tussen C++ en de SCSI bus gebeurdt door ASPI. Dit is een DLL file.
Wat ik denk dat moet gebeuren is het volgende:

De 2 threads moeten om en om toegang krijgen tot de DLL file om data te sturen. Met 2 losse EXE's kan je tegelijk data sturen, dus de DLL file is compatible met re-entring processing. Wat ik een hele mooie uitleg vondt, was die van alarmnummer:
Dit is het punt dat je gaan synchronizen. Je zegt: ik ben nu bij de balie.. ramt de deur naar de balie dicht en zorgt er hiermee voor dat andere mensen niet bij de balie kunnen komen. Als je klaar bent doe je de deur weer open zodat anderen er weer inkunnen. Als jij bij de balie komt en de deur is dicht.. ga je ervoor wachten.. totdat de deur open gaat.
Ik denk dat dat het hele punt is :? Echter ik zou niet zo weten hoe ik dit goed en fatsoenlijk kan doen. Critical section / Mutex / Semaphore heb ik allemaal bekeken, maar geen van alle schijnt goed zijn werk te doen.
Weet iemand hier een goede oplossing voor :? Zoals je misschien wel merkt ben ik zeker niet beroerd om iets uit te leggen (is tenslotten leerzaam voor mij). Ik probeer echt zoveelmogelijk te prutsen, maar het lukt maar niet... :'( . Hier is de broncode te downloaden(open Threads.cpp & TmyData.cpp, of het project). Het ziet er wat rommelig uit, en misschien weet je dingen beter maar ik ben niet super ervaren en heb het voor elkaar weten te prutsen tot nu toe. Ik vraag niet om een kant en klare script, maar een paar hints/tips zijn echt heel erg welkom! _/-\o_

offtopic:
Jeetje.. ik heb in een week nog nooit zoveel geleerd :D Ben ik echt blij mee 8)

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • TheGhostInc
  • Registratie: November 2000
  • Niet online
IJnte schreef op dinsdag 11 januari 2005 @ 23:18:
[...]
De 2 threads moeten om en om toegang krijgen tot de DLL file om data te sturen. Met 2 losse EXE's kan je tegelijk data sturen, dus de DLL file is compatible met re-entring processing
[...]
Die hele DLL is multithread safe.... oftewel:
*Alle beveiligingen eruit gooien *

Dan werkt je app waarschijnlijk perfect.

Critical section / Mutex / Semaphore heb je alleen nodig om je statusbar te beveiligen als meerdere threads deze aanroepen, maar daar zou ik nog even mee wachten, want de gevolgen zijn denk ik beperkt. Hooguit wat flippende GUI, nothing that windows can't handle ;)

[ Voor 25% gewijzigd door TheGhostInc op 11-01-2005 23:28 ]


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
TheGhostInc schreef op dinsdag 11 januari 2005 @ 23:25:
[...]


Die hele DLL is multithread safe.... oftewel:
*Alle beveiligingen eruit gooien *

Dan werkt je app waarschijnlijk perfect.

Critical section / Mutex / Semaphore heb je alleen nodig om je statusbar te beveiligen als meerdere threads deze aanroepen, maar daar zou ik nog even mee wachten, want de gevolgen zijn denk ik beperkt. Hooguit wat flippende GUI, nothing that windows can't handle ;)
Heb je hier persoonlijk ervaring mee :?. Het lijkt mij echt wel nodig om het een en ander te beveiligen hoor.. Als ik gewoon heel bot een Thread maakt zonder beveiliging, dan krijg ik allemaal foutmeldingen van ASPI > "Overlapped Commands Attempted". Dit komt echt van ASPI af. Dit betekent volgens mij dat 2 commando's gelijktijdig de DLL willenbenaderen / volgooien met variabelen en dat ASPI dat niet pikt.

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

IJnte schreef op dinsdag 11 januari 2005 @ 23:18:
[...]

Mmm weer wat geleerd !!! Ik ben vandaag maar eens overgestap naar het gebruik van een Mutex.
Beetje overbodig, daar je maar in 1 proces werkt een een CriticalSection dus sneller is. Je kunt overigens gewoon de TCriticalSection van VCL gebruiken, maar dan lock je dus niet gericht op activiteiten maar puur op knelpunten.
Ik denk dat dat het hele punt is :? Echter ik zou niet zo weten hoe ik dit goed en fatsoenlijk kan doen. Critical section / Mutex / Semaphore heb ik allemaal bekeken, maar geen van alle schijnt goed zijn werk te doen.
Wedden dat die allemaal hun werk goed doen? ;) Het probleem is dat jij niet helemaal doorhebt hoe multithread synchronizatie in z'n werk gaat :)

Laten we even een praktijkvoorbeeld geven met een stukje code:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
void VerhoogTijd()
{
if(++secondes >= 60)
  {
  secondes = 0;
  if(++minuten >= 60)
    {
    minuten = 0;
    if(++uren >= 24)
      uren = 0;
    }
  }
}

Dit is een zuivere functie die als je 'm strak iedere seconde aanroept een correcte klok zal geven. Echter, stel nu dat je een aparte thread hebt die deze functie iedere seconde aanroept, en vanuit threads de huidige tijd opvraagt. SMP daargelaten kan een computer niet 2 dingen tegelijk doen, hij faket multitasking door omstebeurt steeds stukjes code uit een andere actieve thread uit te voeren. Oftewel Thread A is even aan de beurt, status van A wordt opgeslagen, dan mag B even, en C etc. etc., totdat Thread A weer even de CPU mag misbruiken. Het springen tussen de threads heet een 'task switch', 'thread switch' of 'context switch'.

In de meeste gevallen gaat het nu goed als de TimerThread netjes die tijd verhoogt en anderen het uitlezen. Echter, stel nu dat het 13:59:59 is, dan de functie VerhoogTijd wordt aangeroepen, en vervolgens na regel 8 een thread switch plaatsvindt naar een thread die de tijd uitleest? Deze zal op dat moment 13:00:00 als tijd uitlezen, oftewel ronduit fout! Als je het nog strakker timed kun je zelfs 24:00:00 of 13:60:00 als tijden krijgen, waardes die de 'invariant' van een tijd overtreden.

Op dit moment heb je dus synchronizatie nodig. Je maakt een Critical Section of Mutex (MUTual EXclusion oftewel wederzijdse uitsluiting) aan, wat een object is dat je vanuit alle threads benadert. Vervolgens ga je bij iedere gelegenheid dat je de thread-unsafe variabelen (secondes, minuten en uren in dit geval) benadert locken op die mutex. Oftewel als volgt:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HANDLE     hMutex;    // Elders gedefinieerd

void VerhoogTijd()
{
WaitForSingleobject(hMutex, INFINITE);
... functie als hierboven ....
ReleaseMutex(hMutex);
}

void HoeLaatIsHet(int &uur, int &min, int &sec)
{
WaitForSingleobject(hMutex, INFINITE);
uur = uren;
min = minuten;
sec = secondes;
ReleaseMutex(hMutex);
}

Op deze manier kan er wel een thread switch plaatsvinden tijdens de timer thread, maar die heeft op dat moment de mutex in bezit. Dan komt thread B die HoeLaatIsHet aanroept, maar die gaat op dat moment 'infinite' zitten wachten tot de mutex vrij komt... die in het bezit is van de timerthread! Ergo B gaat in wait state, thread A komt vanzelf weer aan de beurt, en zodra die de mutex vrijgeeft mag B pas aan de variabelen komen. Ineens zijn we threadsafe bezig :)

Ik hoop dat het met deze uitleg wat helderder is :P Vergeet overigens niet aan goeie exception handling te doen, het mag nooit gebeuren dat je door een exception vergeet een Mutex of ander synchronizatieobject vrij te geven: dan knoopt je hele programma zich op.

Een ander pijnlijk fenomeen dat je bij synchronizatie tegen gaat komen is deadlocking (of nog zeldzamer livelocking en thread starvation). Lees eens voor de lol over de dining philosophers zodat je ook die problemen snapt :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
_/-\o_ _/-\o_ _/-\o_ _/-\o_ _/-\o_ Hij doet et een heeeeeel stuk beter :*) . Ik kan nu 2 apparaten tegelijk testen :Y) . Ik heb erg veel aan je tips gehad.. Na veel prutsen heb ik het volgende gemaakt:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Mutex = CreateMutex(NULL, False, NULL);
Result = WaitForSingleObject(Mutex,INFINITE);

if(Result == WAIT_OBJECT_0)
{
ModeselectBlock();
ReleaseMutex(Mutex);
}

for(int p=0;p <=10000;p++)
{
  Mutex = CreateMutex(NULL, False, NULL);
  Result=WaitForSingleObject(Mutex,INFINITE);

  if(Result == WAIT_OBJECT_0)
  {
  SchrijfData();
  ReleaseMutex(Mutex);
  }
}

Dit werkt dus O-) . Het is misschien niet de mooiste methode, maar het werkt wel... Alleen waar ik nog een probleem mee heb zijn de deadlocks e.d..
Ik hoop dat het met deze uitleg wat helderder is Vergeet overigens niet aan goeie exception handling te doen, het mag nooit gebeuren dat je door een exception vergeet een Mutex of ander synchronizatieobject vrij te geven: dan knoopt je hele programma zich op.
Ik maak een soort testprogrammatje wat het apparaat test. Er kunnen dus ook fouten voorkomen. Zie voor de foutafhandeling hier.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(srbExec.SRB_Status != SS_COMP)                             // Check if the ASPI command is executed succesfull 
   { 
    Check = true; 
    MessageBox (NULL,"Write Error","Fatal error", MB_ICONERROR );                              // If not show MessageBox > "Error Data Send" 
    SenseKey = srbExec.SenseArea[2]; 
    SenseKey = SenseKey & 15; 
    ASC = srbExec.SenseArea[12]; 
    ASCQ = srbExec.SenseArea[13]; 
    SenseData(SenseKey,ASC,ASCQ); 
    char Errorcode1[50]; 
    AnsiString ErrorCode2; 
    ErrorCode2 = Form1->ErrorCode; 
    sprintf(Errorcode1,"%s",ErrorCode); 
    MessageBox (NULL,Errorcode1,"ErrorCode", MB_ICONERROR ); 
   } 

Als er een fout optreedt dan krijg ik een soort foutcode van het apparaat. In de functie SenseData ( SenseData(SenseKey,ASC,ASCQ); ) staan alle foutcodes + foutmelding. Als er een fout is springt hij dus naar een andere functie. Hierin gaat het weer fout. Ik krijg de foutcode netjes, maar de Thread zelf sluit niet af. Dat zie in in de Thread Monitor. Hoe kan ik er voor zorgen dat de thread stops (Terminated) en dat ik de Mutex altijd afsluit dan (de-constuctor misschien :? ).
Echt bedankt vast!

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Ik ben weer een stuk verder gekomen ;). Het lukt me nu om bij een foutmelding de 2 threads elkaar niet te laten beinvloeden. Er is echter 1 raar ding.
Als apparaat A een foutmelding geeft dan gaat apparaat B gewoon door met testen. Als apparaat B een foutmelding geeft, dan gaat apparaat A ook door met testen, maar op een gegeven moment stop hij gewoon. De Thread loopt nog, maar er gebeurd helemaal niks meer. De Thread hangt dus.
Hoe kan ik met een soort Catch > Try combinatie of iets anders, ervoor zorgen dat een thread die hangt (b.v. na 20 sec) wordt geterminated :?

Alvast bedankt :9

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • The End
  • Registratie: Maart 2000
  • Laatst online: 20:11

The End

!Beginning

IJnte schreef op donderdag 13 januari 2005 @ 11:14:
Ik ben weer een stuk verder gekomen ;). Het lukt me nu om bij een foutmelding de 2 threads elkaar niet te laten beinvloeden. Er is echter 1 raar ding.
Als apparaat A een foutmelding geeft dan gaat apparaat B gewoon door met testen. Als apparaat B een foutmelding geeft, dan gaat apparaat A ook door met testen, maar op een gegeven moment stop hij gewoon. De Thread loopt nog, maar er gebeurd helemaal niks meer. De Thread hangt dus.
Hoe kan ik met een soort Catch > Try combinatie of iets anders, ervoor zorgen dat een thread die hangt (b.v. na 20 sec) wordt geterminated :?

Alvast bedankt :9
Je kan beter tijd stoppen in het onderzoeken waarom die thread hangt na een tijdje, dan dat je allerlei workarounds gaat bedenken.

Een thread hoort zichzelf te terminaten. Of uitzichzelf of in opdracht van een andere thread. Je weet nooit wat er gebeurd als je een thread (hard) terminate binnen een process. Wordt b.v. al het gealloceerde geheugen vrijgegeven? Worden alle handles gesloten, enz.

  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
The End schreef op donderdag 13 januari 2005 @ 11:32:
[...]


Je kan beter tijd stoppen in het onderzoeken waarom die thread hangt na een tijdje, dan dat je allerlei workarounds gaat bedenken.

Een thread hoort zichzelf te terminaten. Of uitzichzelf of in opdracht van een andere thread. Je weet nooit wat er gebeurd als je een thread (hard) terminate binnen een process. Wordt b.v. al het gealloceerde geheugen vrijgegeven? Worden alle handles gesloten, enz.
Jah ben ik idd met je eens.. Ik kan er alleen niet achterkomen hoe ik hebt programma in steps kan laten lopen (zoals dat ook bij VB kan). Er zit wel een Step over in, maar echt fatsoenlijk debuggen kan ik niet met Borland heb ik het idee...

Er lopen 2 threads tegelijk. Ze hebben beide dezelfde class, maar de meeste variabelen staan private en protected. Volgens mij kunnen de variabelen elkaar niet beinvloeden. Misschien hangt er een mutex :?

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Is dit trouwens wel goed :?
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Mutex = CreateMutex(NULL, False, NULL);
Result = WaitForSingleObject(Mutex,INFINITE);

if(Result == WAIT_OBJECT_0)
{
ModeselectBlock();
ReleaseMutex(Mutex);
}

for(int p=0;p <=10000;p++)
{
  Mutex = CreateMutex(NULL, False, NULL);
  Result=WaitForSingleObject(Mutex,INFINITE);

  if(Result == WAIT_OBJECT_0)
  {
  SchrijfData();
  ReleaseMutex(Mutex);
  }
}


Hij maakt steeds een nieuwe mutex aan... De Handle Mutex staat in het Public gedeelte van de class.. Doe ik dit goed :?

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Uhm nee dat doe je niet goed 8)7

Ik heb nu heel weinig tijd, dus als iemand anders even de honneurs kan waarnemen? :) Iig is het natuurlijk de bedoeling dat je vanuit verschillende plekken op dezelfde mutex lockt, CreateMutex roep je als het goed is maar 1 keer aan in je hele programma voordat je uberhaupt een thread de lucht inschopt :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Dat dacht ik al... Als je goed beredeneerd kan het ook eigenlijk niet :( .
Hoe kan ik dan die mutex gebruiken :? ik kan hem aanmaken, en op wachten, vrijgeven maar niet locken :?

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Okee ik heb wat meer tijd :)

Een Mutex object zoals je dat aanmaakt met CreateMutex moet je zien als een estafette-stokje. D'r zijn 4 mensen die graag een rondje op de baan willen rennen, maar er mag er maar 1 tegelijk op anders krijg je een corrupte uitslag. Ergo zodra het startschot gaat beginnen er 4 threads te lopen, die alle 4 een INFINITE wait doet op het stokje. 1 ervan krijgt 'm en gaat z'n rondje lopen. Aan het einde van z'n rondje doet ie een ReleaseMutex op het stokje, en direct krijgt 1 van de waiting threads hem te pakken. Deze doet z'n rondje, en zodra ie rond is staat de eerste thread er niet op te wachten, dus die kan 'm niet krijgen, maar de volgende loper krijgt 'm wel. Enzovoorts :)

De hele essentie is dus dat de Mutex een shared objects is, en doordat threads middels WaitForSingleObject netjes wachten totdat ze het enige aanwezige stokje in handen krijgen is er continu maar 1 loper op de baan, waardoor ze niet met elkaar botsen of andere corruptie veroorzaken.

Als je echter een 'gewone' race wil lopen waarbij alle 4 de lopers in een andere baan lopen, dan delen ze dus geen resources, kunnen ze elkaar niet in de weg lopen, en hoef je dus niet te synchronizeren. Ergo er is alleen een 'stokje' nodig als men niet tegelijk dezelfde baan of resource mag gebruiken.

Snappu? :)

Professionele website nodig?


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

IJnte schreef op donderdag 13 januari 2005 @ 13:28:
Dat dacht ik al... Als je goed beredeneerd kan het ook eigenlijk niet :( .
Hoe kan ik dan die mutex gebruiken :? ik kan hem aanmaken, en op wachten, vrijgeven maar niet locken :?
Kijk de docs van WaitForSingleObject nog eens na ;) Zodra je een succesvolle Wait hebt gedaan op een synchronization object is ie van jou, en dus door die thread gelockt :)

Professionele website nodig?


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Volgens mij moet de TS heel snel een goed C++ boek gaan lezen. Ondanks de waarschuwing van curry684 vergeet hij toch de else-branch van de if(Result == WAIT_OBJECT_0), en wie doet dan de ReleaseMutex( )? Oftewel, gebruik een object ctor/dtor ipv een paar van C functies.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Nou wat ik niet helemaal snap is dat ik createmutex(naam) in mijn main form. Daarna in mijn threads gebruik ik alleen waitforsingleobject en releasemutex. Krijgt hij met waitforsingel object automatisch de mutex inhanden :? B.v. met cricital sections heb je echt een onderscheid in lock en release, terwijl een mutex dat niet schijnt te hebben.
Het probleem is gewoon dat als ik b.v. met een rewind command bezig ben, de thread wacht (met een handle) totdat er een signaal terug is van het apparaat dat hij klaar is met rewinden. Ondertussen wil ik graag data kunnen schrijven naar een andere apparaat..

Wat ik dus kan doen in in het mainform de CreateMutex inzetten. In de threads bij elke loop WaitForSingleObject en Releasemutex(Form1->Mutex) doen :?

offtopic:
Ik kan wel wat hulp gebruiken zie ik :( begin echt gefrustreerd te raken)...

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
MSalters schreef op donderdag 13 januari 2005 @ 13:37:
Volgens mij moet de TS heel snel een goed C++ boek gaan lezen. Ondanks de waarschuwing van curry684 vergeet hij toch de else-branch van de if(Result == WAIT_OBJECT_0), en wie doet dan de ReleaseMutex( )? Oftewel, gebruik een object ctor/dtor ipv een paar van C functies.
Euh.. Ik heb het officiele boek van Borland C++ Builder 6.0 aangeschaft. Is een boek van meer dan 1000 pagina's waar maar met een halve pagina over de mutex wordt gesproken. Op internet is er theoretisch wel wat te vinden, maar praktisch vrij weinig. :X

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • The End
  • Registratie: Maart 2000
  • Laatst online: 20:11

The End

!Beginning

Er zit toch ook documentatie bij de verschillende calls?

In de MSDN staat bijvoorbeeld heel duidelijk dat als je CreateMutex aanroept, dat je daarna (ooit) CloseHandle op de verkregen mutex moet doen. Anders lekt je programma handles.

Je kan trouwens een mutex e.d. gewoon hergebruiken. Je hoeft niet steeds een nieuwe aan te maken. Waarom gebruik je trouwens niet gewoon events om te signalen? (CreateEvent)

  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
The End schreef op donderdag 13 januari 2005 @ 14:24:
Er zit toch ook documentatie bij de verschillende calls?

In de MSDN staat bijvoorbeeld heel duidelijk dat als je CreateMutex aanroept, dat je daarna (ooit) CloseHandle op de verkregen mutex moet doen. Anders lekt je programma handles.

Je kan trouwens een mutex e.d. gewoon hergebruiken. Je hoeft niet steeds een nieuwe aan te maken. Waarom gebruik je trouwens niet gewoon events om te signalen? (CreateEvent)
De functie zelf maakt ook al gebruik van een event. Dan zou een Event moeten wachten op een Event wat er als nog voor zorgt dat de boel zwaar vertraagd wordt lijkt mij..

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Minder assumpties maken en meer docs lezen ;)

Als je iets wil signallen moet je een Event gebruiken (en da's iets anders dan een event in je GUI), als je iets wil beschermen tegen multiple access een Mutex, en als je iets wil beschermen tegen multiple access van meer dan X bronnen een Semaphore.

En bij de docs van WaitForSingleObject (tip: MSDN Library Online, zie vooral de 'About' en 'Using' secties) staat helder dat je met een Wait het object automatisch signalled oftewel in handen krijgt (zoals ik een stuk hierboven ook al meldde).

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Ik heb het even goed doorgelezen. Bedankt voor de informatie. Ik ben ook even bij de volgende link blijven hangen: MSDN. Daar gebruiken ze ook een mutex en waitforsingleobject. Wat voor mij even een punt is, is dat die Mutex overal toegangelijk is lijkt het. Ik weet even niet hoe ik precies die mutex moet declareren. Ik denk dat ik in TForm1 de functie CreateMutex moet zetten, en in de threads moet verwijzen naar de mutex in TForm1.

Het eerste grijzen blok uit de link van MSDN moet dus in Tform1 en het 2e grijze blok moet dus in de thread zelf :? Ik hoop dat ik het zo goed begrijp. Ik hoop dat ik het dan ook kan gebruiken ;)

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Je kunt natuurlijk ook vanuit de class die de threads aanmaakt aan alle threads een referentie naar de shared mutex meegeven ;) Maar inderdaad, het idee is dat alle threads op dezelfde mutex synchronizeren alvorens shared data te gebruiken. De mutex is zeg maar gebonden aan de data die hij beschermt (1 mutex per te beschermen 'eenheid' aan data) en niet aan de thread :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
curry684 schreef op donderdag 13 januari 2005 @ 15:51:
Je kunt natuurlijk ook vanuit de class die de threads aanmaakt aan alle threads een referentie naar de shared mutex meegeven ;) Maar inderdaad, het idee is dat alle threads op dezelfde mutex synchronizeren alvorens shared data te gebruiken. De mutex is zeg maar gebonden aan de data die hij beschermt (1 mutex per te beschermen 'eenheid' aan data) en niet aan de thread :)
;) Ik heb het net weer effe goed op papier gezet. Er moet inderdaad 1 vlag zijn die de status aangeeft of een thread bezig is of niet. Deze vlag gebruik ik dan in de vorm van een mutex.
In de form load zet ik hMutex = CreateMutex(NULL, false, NULL). De handle hMutex staat in de public sectie van Tform1. In de threads verwijs ik met Form1->hMutex naar de mutex in het mainform. Echter ik denk niet dat ik dit goed doe :? Ik moet een soort globale variabele maken, die overal toegangelijk is. Ik heb het wel eens gemaakt, maar ben vergeten hoe..
In de Threads zet ik voordat ik elke functie aanroep de waitforsingleobject(Form1->hMutex, INFINITE), en na de aanroep van de functie ReleaseMutex. Op deze manier lijkt mij iig dat ik om en om de "vlag" in het mainform benader.. Is dit een domme methode :?

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Even alleen op je laatste zin: als alle functies thread-unsafe zijn is het correct, ik vraag me dan alleen af wat in godesnaam nog het nut is van tig threads gezien het feit dat je dan alles serializeert :)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Idd het is raar dat het zo moet he... Ik moet met 2 threads 2 apparaten aansturen over 1 bus ;). Ik heb een singlethreaded programma gemaakt, maar dat kan maar 1 apparaat aansturen. Als ik dit programma 2x opstart (de EXE dus) dan kan ik wel tegelijk de apparaten aansturen.
De DLL file moet dit dus wel aankunnen.
Echter als ik een singlethreaded programma maak dan euh kan ik nix meer met de GUI doen (vandaar ook topic title GUI en Data). Als ik synchronize gebruik dan kan maak je er dus een soort singlethreaded programma van en dan kan ik ook niet de met de GUI iets doen.
Met het multi-threaded programma kan dat dus wel B) .

Met 2 EXE's verdeelt windows automatisch de processortijd tussen de verschillende EXE's. Wat er eigenlijk moet gebeuren is dat ik eigenlijk de functie van 2 exe's(Tegelijk data sturen naar 2 apparaten over 1 bus) gecombineerd moet worden in een programma wat 2 threads heeft, en waarmee ik nog iets kan met de GUI 8)7. Het sturen van data is het probleem gelukkig niet meer, maar het op de juiste manier verdelen van taken door de verschillende Threads is dus wel het probleem. Aangezien er bar weinig info is, probeer ik door de tips die ik hier krijg stukje bij beetje verder te komen (zit wel nog wat tijdsdruk achter maar goed..).
Hoop het zo goed uitgelegd te hebben :Y).
Mep me maar als ik het echt verkeerd bedenk ;).
offtopic:
Ik wordt weer het lokaal uitgeschopt :X . Thuis maar weer verder ;)

[ Voor 8% gewijzigd door IJnte op 13-01-2005 17:29 ]

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
IJnte schreef op donderdag 13 januari 2005 @ 14:08:
[...]

Euh.. Ik heb het officiele boek van Borland C++ Builder 6.0 aangeschaft. Is een boek van meer dan 1000 pagina's waar maar met een halve pagina over de mutex wordt gesproken. Op internet is er theoretisch wel wat te vinden, maar praktisch vrij weinig. :X
Het gaat niet om de mutex, het gaat om het principe van rotzooi maken = opruimen. Deftiger gezegd, Resource Acquisition Is Initialization (RAII). De implementatie in C++ gebeurt met constructors en destructors. Een destructor is lastig te vergeten, ongeveer de enige manier is een new zonder delete - en dat spotten wij snel genoeg.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Heeft Iemand nog tips misschien :? Het feit dat ie met 3 exe's wel werkt, dat geeft wel aan dat de DLL file multi-threaded is. Hoe kan ik het zo maken dat ik de functies van 3 exe's in 1 programma maakt :?

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Nee, dat geeft het niet aan.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Tipje: tussen processen heb je 'process space boundaries'. Threads binnen 1 process opereren in dezelfde process space.

Food for thought ;)

Professionele website nodig?


  • IJnte
  • Registratie: Juni 2003
  • Laatst online: 16-05 23:54
Mmm leuke stuf ;). Kheb er wat over gelezen, maar et is wel heel pittig hoor..

Nog een domme vraag misschien. Heeft processorarchitectuur nog iets te maken met multi-threading :?. Ik snap dat Hyper Threading hier wel effect op heeft, maar stel dat ik alles maak & test met een Intel Pentium 2 (450mhz), en dat ik de software daarna zou gebruiken op een AMD Athlon XP 2100+, zou er verschil zitten in hoe de processor de zaak afhandeld (denkende aan MMX e.d.) :?

Exploring the world by bicycle! cyclingsilk.wordpress.com


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Nee dat handelt je compiler af :) Je zou hoogstens verschillende race conditions kunnen krijgen op verschillende architecturen, maar dat zijn hoe dan ook bugs, die zich enkel op andere manieren manifesteren :)

Professionele website nodig?

Pagina: 1