Hinweis: Das Forum wird geschlossen! Neue Registrierungen sind nicht mehr möglich!

 Zurück zu Pro-Linux   Foren-Übersicht   FAQ     Suchen    Mitgliederliste
Thread-Probleme
Gehen Sie zu Seite 1, 2  Weiter
 
Neuen Beitrag schreiben   Auf Beitrag antworten    Pro-Linux Foren-Übersicht -> Programmieren - C
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
WilliWupp
Gast





BeitragVerfasst am: 28. Feb 2008 12:56   Titel: Thread-Probleme

Hi,

ich habe hier eigentlich ein recht simples stück Code um Threads zu erzeugen:

Code:
bool startThread(void* func(void*),void *arg,FILE *logHandle)
{
pthread_attr_t attr;
pthread_t      thread;
int            r;

pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
r = pthread_create(&thread,&attr,func,arg);
pthread_attr_destroy(&attr);
if (r)
   {
   showLog(logHandle,"Error: could not create thread (%d)",r);
   return false;
   }
return true;
}


Alternativ dazu sogar noch einfacher:

Code:
bool startThread(void* func(void*),void *arg,FILE *logHandle)
{
pthread_t      thread;
int            r;

r = pthread_create(&thread,NULL,func,arg);
if (r)
   {
   showLog(logHandle,"Error: could not create thread (%d)",r);
   return false;
   }
return true;
}


Bei beiden habe ic hdas Problem dass ich nur ca. 150 Threads starten kann, dann schlägt das pthread_create() mit einem Fehler 12 fehl. Speicher ist genug da, the Posix-Max-Threads sind unlimited und in /proc ist die Anzahl der Threads auch nicht begrenzt. Was kann also die Ursache dafür sein?
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 28. Feb 2008 13:13   Titel:

Die Variable "thread", in der die notwendigen Datenstrukturen zur Verwaltung des Threads aufbewahrt werden, liegt bei dir im Stackframe der Funktion startThread(). Damit ist sie nach Ende der Funktion ungültig, obwohl der Thread noch läuft. Das ist MURKS, und ein SIGSEGV ist nur eine Frage der Zeit.

Du musst mit malloc() Speicher auf dem Heap für die Datenstruktur reservieren, auch wenn du sie in deinem Programm selbst nicht benötigst.

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

WilliWupp
Gast





BeitragVerfasst am: 28. Feb 2008 13:35   Titel:

Aaah...das klingt einleuchtend.

Nur: wie/wann gebe ich den Datenbereich wieder frei? Der Thread weiß davon ja nix...
 

WilliWupp
Gast





BeitragVerfasst am: 28. Feb 2008 13:40   Titel:

Nachtrag: Jetzt sieht der Code so aus - und trotzdem reicht es nur für knapp 300 Threads:

Code:
bool startThread(void* func(void*),void *arg,FILE *logHandle)
{
pthread_attr_t attr;
pthread_t     *thread;
int            r;

errno=0;
thread=(pthread_t*)malloc(sizeof(pthread_t));
if (!thread)
   {
   showLog(logHandle,"Error: could not allocate thread (%d)",errno);
   return false;
   }
r=pthread_attr_init(&attr);
r=pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
r = pthread_create(thread,&attr,func,arg);
pthread_attr_destroy(&attr);
if (r)
   {
   showLog(logHandle,"Error: could not create thread (%d)",r);
   return false;
   }
return true;
}
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 28. Feb 2008 15:57   Titel:

Mit pthread_attr_t attr ist es genau dasselbe!

Diese Struktur ist allerdings konstant und kann auch für mehrere Threads benutzt werden, wenn alle diese Threads dieselben Attribute haben sollen. Du kannst hier also z.B. eine globale Konstante benutzen.

Wenn du in deinem Programm dynamisch Threads erzeugst, musst du dir die Pointer auf die Thread-Datenobjekte irgendwo merken und nach dem Ende des Threads wieder freigeben. Im allgemeinen bastelt man das so, dass der Worker-Thread kurz vor seinem Ende dem Main-Thread signalisiert, dass er sich beenden möchte. Der main-Thread geht dann in ein pthread_join() und wartet auf die korrekte Beendigung des Worker-Threads. Dieser macht dann pthread_exit() und der Main-Thread kommt auf dem pthread_join() mit dem Exitcode des Worker-Threads zurück. Danach kann er dann den Speicher für die Thread-Datenstruktur des jetzt beendeten Worker-Threads freigeben.

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

WilliWupp
Gast





BeitragVerfasst am: 28. Feb 2008 17:35   Titel:

Aaaaalso, pthread_attr_t ist jetzt static da es mit den immer wieder gleichen Parametern verwendet wird.

Trotzdem: mehr als knapp 300 Threads gehen nicht, dann ist Schluss. Woran könnte das noch liegen?
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 29. Feb 2008 12:34   Titel:

Du solltest dir nochmal ein Grundlagenbuch zu C (nicht C++!) schnappen.

Die Speicherklasse "static" bewirkt mitnichten, dass eine Variable "immer mit gleichen Parametern verwendet wird" -- kein Ahnung, was das heißen soll. "static" bedeutet, dass das Symbol außerhalb des Blockes, in dem es definiert wird, unsichtbar ist. Das ist bei funktionslokalen Variablen zwangsläufig der Fall, weil diese mit dem Stackframe der Funktion nach deren Ende ja wieder ungültig werden.

Sinnvoll ist "static" dagegen außerhalb von Blöcken. Ein als "static" markiertes Symbol ist außerhalb des Quellcodefiles unsichtbar.

Zu deinem Problem -- folgender Code funzt:
Code:


#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

pthread_attr_t attr;

void *thread_function(void *arg)
{
   /* Sleep 1000s */
   sleep(1000);

   /* This point should never be reached before the process is terminated...*/
   fprintf(stderr,"Reached a point that should never be reached!");
}

void startThread(void* func(void*), void *arg)
{
   pthread_t     *thread;
   int            r;
 
   if ((thread=(pthread_t*)malloc(sizeof(pthread_t)))==NULL) {
      perror("startThread, malloc");
      exit(EXIT_FAILURE);
   }
   if (pthread_create(thread,&attr,func,arg)==-1) {
      perror("startThread, pthread_create");
      exit(EXIT_FAILURE);
   }
}


int main(int argc, char *argv[])
{
   int i;

   if (pthread_attr_init(&attr)==-1) {
      perror("main, pthread_attr_init");
      exit(EXIT_FAILURE);
   }
   if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)==-1) {
      perror("main, pthread_attr_setdetachstate");
      exit(EXIT_FAILURE);
   }
 
   for(i=0;i<1000;i++) {
      startThread(thread_function,NULL);
      fprintf(stdout,"%d\n",i);
   }

   /* Wait 500s to let the user inspect the example. */
   sleep(500);

   if (pthread_attr_destroy(&attr)==-1) {
      perror("main, pthread_attr_destroy");
      exit(EXIT_FAILURE);
   }
}


Und das Makefile dazu:
Code:

.PHONY: all clean

all: thread
clean:
   -rm thread *.o

thread: thread.o
   $(CC) -lpthread -o $@ $^


Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

Gast
Gast





BeitragVerfasst am: 02. März 2008 14:51   Titel:

Janka hat folgendes geschrieben::
"static" bedeutet, dass das Symbol außerhalb des Blockes, in dem es definiert wird, unsichtbar ist.


Das ist bei Variablen die innerhalb einer Funktion als static definiert werden nur die halbe Wahrheit: diese bleiben zusätzlich auch nach verlassen der Funktion erhalten, sprich man kann auf deren Inhalt später wieder zugreifen. Und noch viel besser: ein

static long i=-1

bewirkt, dass i exakt einmal mit -1 initialisiert wird und nicht etwa bei jedem Aufruf dieser Funktion erneut.
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 02. März 2008 20:18   Titel:

Tatsächlich, du hast recht. Wieder was gelernt! Man kann also auf diese Weise von innerhalb eines Blockes aus globale Variablen definieren, die dann nur innerhalb des Blockes sichtbar sind.

Testcode:
Code:

#include <stdio.h>

#define STATIC static

void f1(int s)
{
  STATIC int a;
  STATIC int b;

  if (s) {
    a=12;
    b=34;
  }

  printf("f1: a: %d, b: %d\n",a,b);
}

void f2(int s)
{
  STATIC int a;
  STATIC int b;

  if (s) {
    a=56;
    b=78;
  }

  printf("f2: a: %d, b: %d\n",a,b);
}


int main(void)
{
  f1(1);
  f2(1);
  f1(0);
  f2(0);
}


Den Unterschied sieht man, wenn man #define STATIC static durch #define STATIC ersetzt.

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

WilliWupp
Gast





BeitragVerfasst am: 03. März 2008 13:24   Titel:

So, egal wie ich es mache, ob "static" in- oder außerhalb der Funktion, ich komme trotzdem nicht über 296 Threads hinaus...
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 03. März 2008 22:18   Titel:

Hast du wenigstens mal mein Beispiel ausprobiert? Das klappt hier nämlich. Wenn es bei dir auch klappt, bau' es schrittweise in deinen Code um und teste nach jedem Schritt. So findet man Fehler, die man zuvor aus lauter Betriebsblindheit nicht gesehen hat.

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

WilliWupp
Gast





BeitragVerfasst am: 05. März 2008 11:04   Titel:

Ja, der Code ist mittlerwile exakt so drin, ohne jede Veränderung...
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 05. März 2008 16:42   Titel:

Dann hast du vermutlich an einer anderen Stelle ein Problem.

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

WilliWupp
Gast





BeitragVerfasst am: 06. März 2008 7:49   Titel:

Naja, ich habe eher bei dir ein Problem entdeckt:

Code:
if (pthread_create(thread,&attr,func,arg)==-1)


Du überprüfst nur auf den Rückgabewert -1 als Fehlerfall, allerdings ist jeder nitch-0-Wert ein Fehler:

Zitat:
If successful, the pthread_create() function shall return zero; otherwise, an error number shall be returned to indicate the error.


Und bei mir gibt es ja auch keine -1 als Fehler sondern eine 12, was dein Beispiel gar nicht bemerkt.
 

Janka



Anmeldungsdatum: 11.02.2006
Beiträge: 3569

BeitragVerfasst am: 07. März 2008 14:06   Titel:

Stimmt, du hast recht. Die pthtread-Funktionen setzen nicht errno, sondern liefern die Fehlernummer direkt zurück. Vermutlich, um "errno" der "normalen" Funktionen nicht zu überschreiben.

Ich erhalte mit einer korrigierten Version meines Programms ebenfalls 12 (ENOMEM) zurück, ab Thread Nummer 381.

Janka
_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
 
Benutzer-Profile anzeigen Private Nachricht senden

Beiträge vom vorherigen Thema anzeigen:   
     Pro-Linux Foren-Übersicht -> Programmieren - C Alle Zeiten sind GMT + 1 Stunde
Gehen Sie zu Seite 1, 2  Weiter
Seite 1 von 2

 
Gehen Sie zu:  

Powered by phpBB © phpBB Group
pro_linux Theme © 2004 by Mandaxy