Der absolute Beginner Thread

Ihr habt ein Problem mit C++ oder anderen Sprachen ? Dann seit Ihr in diesem Forum genau richtig! Hier können alle Fragen gestellt werden, die mit Programmierung (MorphOS, Linux, BeOS, BSD,...) zu tun haben.

Moderatoren: analogkid, roschmyr

eliot
Quasselstrippe
Quasselstrippe
Beiträge: 640
Registriert: 17 Mär 2004, 17:44
Wohnort: Hötzum, bei Braunschweig

Der absolute Beginner Thread

Beitragvon eliot » 29 Jul 2009, 20:24

Hallo,

ich versuche mich verzweifelt in die Amiga Api einzuschießen,
bisher leider mit sehr wenig Erfolg.

Hier mal mein Problem: Nebenläufigkeit (Multithreading).

Code: Alles auswählen

#include<stdio.h>
#include<exec/tasks.h>
#include<unistd.h>

main(int argc, char **argv){
    struct Task *t;
    t =(struct Task *)CreateTask("Task",0,printThread(2,10,3),5000);
   
    printThread(1,10,1);

}

printThread(int threadNumber, int end, int timestamp){
 int i=0;
 sleep(timestamp);
 for(i=0;i<end;i++){
  printf("Thread %i: %i\n",threadNumber,i);
 }
}



Ganz simpel: Zuerts sollte sich Thread 1 melden (kürzerer sleep), danach
Thread 2.

Die Ausgabe ist allerdings:

Thread 2: 0
Thread 2: 1
Thread 2: 2
Thread 2: 3
Thread 2: 4
Thread 2: 5
Thread 2: 6
Thread 2: 7
Thread 2: 8
Thread 2: 9
Thread 1: 0
Thread 1: 1
Thread 1: 2
Thread 1: 3
Thread 1: 4
Thread 1: 5
Thread 1: 6
Thread 1: 7
Thread 1: 8
Thread 1: 9

Wie sich nur unschwer erkennen läßt, ist mit der Nebenläufigkeit essig.
Außerdem bekomme ich beim Auführen ne schöne Warnung vom Log Server.

Wie geht Multithreading (processing) unter Mos?
Ich nutze hier ein Buch von 1989, da es leider nicht wirklich was neueres gibt.
Die Autodocs verraten leider auch nicht viel mehr (Suchen im Heuhaufen).
regards
eliot

Benutzeravatar
Kronos
Moderator
Moderator
Beiträge: 718
Registriert: 07 Sep 2003, 01:10
Wohnort: Hagen

Beitragvon Kronos » 29 Jul 2009, 21:10

Als 1tes wundert mich das PrintF() vom 2ten Task aus funktioniert.....

http://zerohero.homeip.net/~zerohero/autodocs/os3.1/CreateTask_amiga_lib.html schreibt doch ganz klar keine DOS-calls ! Deswegen auch die Hits im Log.

Versuch mal KPrintf() das gibt gleich ins Log aus und ist AFAIR "Thread-safe".

Als nächstes würd ich mi das Beispiel aus dem SDK anschauen (documentation/examples/multithreading).
!! Bin Wichtig !!

eliot
Quasselstrippe
Quasselstrippe
Beiträge: 640
Registriert: 17 Mär 2004, 17:44
Wohnort: Hötzum, bei Braunschweig

Beitragvon eliot » 29 Jul 2009, 21:42

Code: Alles auswählen

#include<stdio.h>
#include<exec/tasks.h>
#include<unistd.h>
#include <dos/dos.h>
#include <dos/dostags.h>

main(int argc, char **argv){
   struct Process *p = (struct Process* )CreateNewProcTags( NP_Entry, printThread(2,10,3),
                               NP_PPCStackSize, 16384,
                               NP_Name, "MyProcess",
                               NP_Priority,4, /* task priority */
                               NP_CodeType, CODETYPE_PPC,
                               TAG_DONE);
  printThread(1,10,0);
}

printThread(int threadNumber, int end, int timestamp){
 int i=0;
 sleep(timestamp);
 for(i=0;i<end;i++){
  printf("Thread %i: %i\n",threadNumber,i);
 }




Ausgabe:

Thread 2: 0
Thread 2: 1
Thread 2: 2
Thread 2: 3
Thread 2: 4
Thread 2: 5
Thread 2: 6
Thread 2: 7
Thread 2: 8
Thread 2: 9
Thread 1: 0
Thread 1: 1
Thread 1: 2
Thread 1: 3
Thread 1: 4
Thread 1: 5
Thread 1: 6
Thread 1: 7
Thread 1: 8
Thread 1: 9

Immerhin, der Hit ist weg, aber die Reihenfolge verwirrt weiterhin?
regards
eliot

Benutzeravatar
Kronos
Moderator
Moderator
Beiträge: 718
Registriert: 07 Sep 2003, 01:10
Wohnort: Hagen

Beitragvon Kronos » 29 Jul 2009, 22:00

/me tippt immer noch auf printf()

Das hat nämlich die Angewohnheit erst dann was auszugeben wenn der Buffer voll ist oder ein RETURN kommt. Wenn diese Unterfunktion nicht aus dem Thread2 geht ist der Ruckizucki fertig und erst danach kommt Thread1 ein schmeisst erst mal den ganzen Buffer auf den Screen....

Versuch mal sowas:
int str_ct = 0
char [20][20];

Und nun in der for-Schleife()

sprintf(str[str_ct++],"Thread %i: %i\n",threadNumber,i);

Dann zur Sicherheit noch ein Delay(100) und Ausgabe:

for(i = 0; i<str_ct;i++)
{
printf("%s",str[i]);
}



 
!! Bin Wichtig !!

Benutzeravatar
Kronos
Moderator
Moderator
Beiträge: 718
Registriert: 07 Sep 2003, 01:10
Wohnort: Hagen

Beitragvon Kronos » 29 Jul 2009, 22:56

Ach und noch nen Nachschlag:

Das Multitasking ist nicht unendlich feinkörnig, d.h. bei 1GHz kann ein Task schon so einiges anstellen bevor im die CPU wieder entzogen wird.

Also am besten den Thread2 was längeres machen lassen (Primzahlen von 1 bis 1.000.000 oder so) und schaun ob Thread ein blockiert wird.
!! Bin Wichtig !!

eliot
Quasselstrippe
Quasselstrippe
Beiträge: 640
Registriert: 17 Mär 2004, 17:44
Wohnort: Hötzum, bei Braunschweig

Beitragvon eliot » 30 Jul 2009, 20:42

Hallo,
hier ein neuer Versuch, da Ergebnis bleibt das gleiche, kein Multitreading

Code: Alles auswählen

int values[20];
int pos=0;

main(int argc, char **argv){
    int i=0;
 struct Process *p = (struct Process* )CreateNewProcTags( NP_Entry, printThread(2,10,4),
                               NP_PPCStackSize, 16384,
                               NP_Name, "MyProcess",
                               NP_Priority,0, /* task priority */
                               NP_CodeType, CODETYPE_PPC,
                               TAG_DONE);
  printThread(1,10,0);
  sleep(6);
  for(i;i<20;i++){
   printf("pos: %i value: %i\n",i,values[i]);
  }
}

printThread(int threadNumber, int end, int timestamp){
 int i=0;
 sleep(timestamp);
 for(i=0;i<end;i++){
    values[pos++]=threadNumber;
  //printf("Thread %i: %i\n",threadNumber,i);
 }
}   



Wieder erst Thread 2, obwohl dieser 4 Sekunden schläft bevor er überhaupt
dran kommt. Irgwndwie scheint das Multiprocessing nicht zu funktionieren.

Nachtrag: Auch mit Delay() funktioert es nicht.

Code: Alles auswählen

int values[20];
int pos=0;

main(int argc, char **argv){
    int i=0;
 struct Process *p = (struct Process* )CreateNewProcTags( NP_Entry, printThread(2,10,4),
                               NP_PPCStackSize, 16384,
                               NP_Name, "MyProcess",
                               NP_Priority,0, /* task priority */
                               NP_CodeType, CODETYPE_PPC,
                               TAG_DONE);
  printThread(1,10,0);
  Delay(6*50);
  for(i;i<20;i++){
   printf("pos: %i value: %i\n",i,values[i]);
  }
}

printThread(int threadNumber, int end, int seconds){
 int i=0;
 Delay(seconds*50);
 for(i=0;i<end;i++){
    values[pos++]=threadNumber;
//  printf("Thread %i: %i\n",threadNumber,i);
 }
}           


EDIT:

Code: Alles auswählen

#include<stdio.h>
#include<exec/tasks.h>
//#include<unistd.h>
#include <dos/dos.h>
#include <dos/dostags.h>


int values[20];
int pos=0;

printThread(){
 int i=0;
// Delay(2*50);
 for(i=0;i<10;i++){
    printf("Thread %i: %i\n",2,i);
 }
}

main(int argc, char **argv){
    int i=0;
 struct Process *p = (struct Process* )CreateNewProcTags( NP_Entry, &printThread,
                               NP_PPCStackSize, 16384,
                               NP_Name, "MyProcess",
                               NP_Priority,5, /* task priority */
                               NP_CodeType, CODETYPE_PPC,
                               TAG_DONE);
  for(i=0;i<10;i++){
    printf("Thread %i: %i\n",1,i);
  }
  Delay(20*50);
  //for(i;i<20;i++){
   //printf("pos: %i value: %i\n",i,values[i]);
  //}
}   

Zuletzt geändert von eliot am 30 Jul 2009, 21:41, insgesamt 1-mal geändert.
regards
eliot

Benutzeravatar
Kronos
Moderator
Moderator
Beiträge: 718
Registriert: 07 Sep 2003, 01:10
Wohnort: Hagen

Beitragvon Kronos » 30 Jul 2009, 21:38

Naja, wenn beide Tasks fast zeitgleich "printThread" aufrufen und dann die gleiche Zeit warten ist das Ergebnis natürlich das selbe.....

Also bitte:

Beider Task Unterschiedliches machen lassen. Und nach möglichkeit etwas was lange dauert.

Ich sach mal eine Funktion Print1Thread mit Delay(50) in der for-Schleife und eine Funktion Print2Thread mit Delay(100).

Zur Sicherheit noch KPrintF() nutzen (musste mit Debug linken), dann sollten (langsam) und abwechselnd die Werte kommen.
!! Bin Wichtig !!

eliot
Quasselstrippe
Quasselstrippe
Beiträge: 640
Registriert: 17 Mär 2004, 17:44
Wohnort: Hötzum, bei Braunschweig

Beitragvon eliot » 30 Jul 2009, 22:36

So geht´s:

Code: Alles auswählen

#include<stdio.h>
#include<exec/tasks.h>
#include <dos/dos.h>
#include <dos/dostags.h>


int values[10];
int pos=0;

printThread(){
 int i=0;
 Delay(2*50);
 for(i=0;i<10;i++){
    values[pos++]=2;
 }
}

main(int argc, char **argv){
    int i=0;
 struct Process *p = (struct Process* )CreateNewProcTags( NP_Entry, &printThread,
                               NP_PPCStackSize, 16384,
                               NP_Name, "MyProcess",
                               NP_Priority,5, /* task priority */
                               NP_CodeType, CODETYPE_PPC,
                               TAG_DONE);
  for(i=0;i<10;i++){
  values[pos++]=1;
  }
  Delay(4*50);
  i=0;
  for(i;i<20;i++){
   printf("pos: %i value: %i\n",i,values[i]);
  }
}



Danke für die Hilfe, es kommen aber bestimmt noch weitere Fragen ;)
Gemachte Feher:
-Thread muss Signatur void name(void) haben.
-printf im weitere Task schreibt ineine andere Shelll
-CreateNewProcTags muss ein Pointer der Methode übergeben werden,
nicht die die Methode.
-Gebaut mit gcc -Lauto, da die Libraries nicht geladen werden.
regards
eliot

eliot
Quasselstrippe
Quasselstrippe
Beiträge: 640
Registriert: 17 Mär 2004, 17:44
Wohnort: Hötzum, bei Braunschweig

Beitragvon eliot » 31 Jul 2009, 21:57

Hallo,

heute: Screen öffnen. hier meine Lösung, welche aber betsimmt alles andre
als optimal ist:

Code: Alles auswählen

#include <graphics/gfxbase.h>
#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
#include <cybergraphx/cybergraphics.h>
#include <clib/asl_protos.h>
#include <clib/cybergraphics_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <dos/dos.h>

struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;

struct NewScreen myScreen={
 0,
 0,
 1024,
 768,
 8,
 0,
 1,
 NULL,
 CUSTOMSCREEN,
 NULL,
 "Test",
 NULL,
 NULL
};

int main(int argc, char **argv){
   struct Screen *scr;

   GfxBase  = (struct GfxBase*)OpenLibrary("graphics.library",39L);
   IntuitionBase =(struct IntuitionBase*)OpenLibrary("intuition.library",39L);
   

   if(GfxBase==NULL){
     printf("Could not open graphics.library\n");
     return -1;
   }

   if(IntuitionBase==NULL){
     printf("Could not open intuition.library\n");
     return -1;
   }

   if((scr=(struct Screen*)OpenScreen(&myScreen))!=NULL){
     printf("Ok\n");
     Delay(20*50);
     CloseScreen(scr);
   } else {
    printf("Something went wrong!\n");
   }

   printf("Graphics library was load successful!\n");
   CloseLibrary(&GfxBase->LibNode);

   return 0;
}

regards
eliot

Benutzeravatar
geit
Seniormember
Seniormember
Beiträge: 857
Registriert: 30 Mär 2006, 12:17
Wohnort: 48477 Hörstel
Kontaktdaten:

Beitragvon geit » 01 Aug 2009, 15:16

Hier mal eine saubere Lösung für das Screen Beispiel.

Änderungen:

1.) Sinnvolles Fehlerhandling. (erlaubt später einfaches implementieren von Locale support)

2.) es werden <proto/libname.h> included. clib/ ist nur für CLIBs. Auch wenn das hier funktioniert, muß das nicht funktionieren. Daher gleich richtig angewöhnen.

3.) Die Screenstruktur wurde wegoptimiert.

4.) PrintF Funktion wurde durch VPrintF ersetzt. Dadurch wird das Program deutlich kürzer.

5.) diverse Leerzeilen, Leerzeichen, Kommentare, Funktionsheader und Klammern eingefügt. Variablennamen verlängert. Dadurch wird das ganze deutlich lesbarer.

6.) Die ersten drei Zeilen erlauben das kompilieren des Quellkodes aus der Shell durch einfaches "execute examplescreen.c". Das macht die Sache einfacher und übersichtlicher.

Den Graphics.library Kram hab ich dringelassen, weil man so schon mal eine Basis für weitere Examples hat. (z.B. das Zeichnen in Fenstern)

Code: Alles auswählen

;/* examplescreen
gcc -noixemul -W -O3 -Wall -mstring -mmultiple  -Wcomments -Wpointer-arith examplescreen.c -o examplescreen
quit
*/

#include <exec/types.h>
#include <clib/alib_protos.h>
#include <graphics/rpattr.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>

#include <proto/muimaster.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/utility.h>

/***********************************************************************************/

struct GfxBase       *GfxBase;
struct IntuitionBase *IntuitionBase;

/***********************************************************************************/

enum{
MSG_ERROR_NOERROR = 0,
MSG_ERROR_GRAPHICS,
MSG_ERROR_INTUITION,
MSG_ERROR_SCREEN,
};

STRPTR TAB_ERRORS[] = {
   "",
   "Unable to open 'graphics.library'!",
   "Unable to open 'intuition.library'!",
   "Unable to open screen!",
};

/* /// main()
**
*/

/***********************************************************************************/

int main( void )
{
struct Screen *screen;
int result;

   result = MSG_ERROR_GRAPHICS;
   if( (GfxBase = (struct GfxBase *) OpenLibrary( "graphics.library", 39 ) ) ) {

      result = MSG_ERROR_INTUITION;
      if( (IntuitionBase = (struct IntuitionBase *) OpenLibrary( "intuition.library", 39 ) ) ) {

         result = MSG_ERROR_SCREEN;
         if( (screen = (struct Screen*) OpenScreenTags( NULL, SA_Width, 1024, SA_Height, 768, SA_Title, "Test", TAG_DONE ) ) ) {

            VPrintf("Ok\n", &result );
            Delay( 20 * 50 );

            result = MSG_ERROR_NOERROR;

            CloseScreen( screen );
         }
         CloseLibrary( &IntuitionBase->LibNode );
      }
      CloseLibrary( &GfxBase->LibNode );
   }

   if( result ) {
      VPrintf( TAB_ERRORS[ result ], &result );
      result = 20;
   }
   return( result );
}
/* \\\ */
[/code]

eliot
Quasselstrippe
Quasselstrippe
Beiträge: 640
Registriert: 17 Mär 2004, 17:44
Wohnort: Hötzum, bei Braunschweig

Beitragvon eliot » 04 Aug 2009, 19:35

Hallo,

vielen Danke für Mühe Geit!
Ich habe ein wenig weiter experimentiert:

Code: Alles auswählen

            VPrintf("Ok\n",&result);

                SetRGB4(&screen->ViewPort,0,0,0,0);
                ClearScreen(&screen->RastPort);

                Draw(&screen->RastPort,640,480);     



Hintergrundfarbe setzen, Screen leeren, Linie von links oben nach rechts unten zeichnen.

Jetzt stellen sich mir folgende Fragen:

Wo liegt der Unterschied zwischen einem RastPort und einem ViewPort?
Was hat es mit den Registern bei setRGB auf sich?
Farben werden wirklich nur von 0-16 gesetzt bei rgb???
Gleiche Frage stellt sich mir bei setPen... mit den Farben und Registern?

regards
eliot
regards
eliot

Benutzeravatar
geit
Seniormember
Seniormember
Beiträge: 857
Registriert: 30 Mär 2006, 12:17
Wohnort: 48477 Hörstel
Kontaktdaten:

Beitragvon geit » 04 Aug 2009, 21:48

eliot hat geschrieben:Hallo,

vielen Danke fuer Muehe Geit!
Ich habe ein wenig weiter experimentiert:

Code: Alles auswählen

    VPrintf("Ok\n",&result);

                SetRGB4(&screen->ViewPort,0,0,0,0);
                ClearScreen(&screen->RastPort);

                Draw(&screen->RastPort,640,480);     



Hintergrundfarbe setzen, Screen leeren, Linie von links oben nach rechts unten zeichnen.

Jetzt stellen sich mir folgende Fragen:

Wo liegt der Unterschied zwischen einem RastPort und einem ViewPort?
Was hat es mit den Registern bei setRGB auf sich?
Farben werden wirklich nur von 0-16 gesetzt bei rgb???
Gleiche Frage stellt sich mir bei setPen... mit den Farben und Registern?


ViewPort ist Screen basiert und sehr lowlevel. Darueber werden zum Beispiel
Darstellungen von mehreren Aufloesungen auf einem Bildschirm geloest, wie man das
aus Klassikhardware oft gefunden hat.

Braucht man eigentlich nicht. Das kann man alles ueber den Rastport realisieren.
Das ist auch nicht lowlevel. SetAPen(), SetBPen(), SetABPenDrMd(). Blit#?,
RectFill() etc.

Also fuer obigen Fall

Code: Alles auswählen

  VPrintf("Ok\n",&result);
   SetBPen( &screen->RastPort, 0 );
   RectFill( &screen->RastPort, 0, 0, 1023, 767 );
   Move( &screen->RastPort, 0, 0 );
   Draw(&screen->RastPort,640,480);


Zurück zu „Code-Küche“



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste