Pro-Linux.de

Pro-Linux

Pro-Linux Diskussions- und Hilfeforum
Aktuelle Zeit: 21. Nov 2018 19:10

Alle Zeiten sind UTC+01:00




Ein neues Thema erstellen  Auf das Thema antworten  [ 21 Beiträge ]  Gehe zu Seite 1 2 Nächste
Autor Nachricht
 Betreff des Beitrags: Thread-Probleme
BeitragVerfasst: 28. Feb 2008 12:56 
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?


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 28. Feb 2008 13:13 
Offline
Benutzeravatar

Registriert: 11. Feb 2006 19:10
Beiträge: 3569
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.


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 28. Feb 2008 13:35 
Aaah...das klingt einleuchtend.

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


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 28. Feb 2008 13:40 
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;
}


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 28. Feb 2008 15:57 
Offline
Benutzeravatar

Registriert: 11. Feb 2006 19:10
Beiträge: 3569
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.


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 28. Feb 2008 17:35 
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?


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 29. Feb 2008 12:34 
Offline
Benutzeravatar

Registriert: 11. Feb 2006 19:10
Beiträge: 3569
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&#40;void *arg&#41;
&#123;
	/* Sleep 1000s */
	sleep&#40;1000&#41;;

	/* This point should never be reached before the process is terminated...*/
	fprintf&#40;stderr,"Reached a point that should never be reached!"&#41;;
&#125;

void startThread&#40;void* func&#40;void*&#41;, void *arg&#41; 
&#123; 
	pthread_t     *thread; 
	int            r; 
 
	if &#40;&#40;thread=&#40;pthread_t*&#41;malloc&#40;sizeof&#40;pthread_t&#41;&#41;&#41;==NULL&#41; &#123; 
		perror&#40;"startThread, malloc"&#41;;
		exit&#40;EXIT_FAILURE&#41;;
	&#125; 
	if &#40;pthread_create&#40;thread,&attr,func,arg&#41;==-1&#41; &#123; 
		perror&#40;"startThread, pthread_create"&#41;;
		exit&#40;EXIT_FAILURE&#41;;
	&#125; 
&#125;


int main&#40;int argc, char *argv&#91;&#93;&#41;
&#123;
	int i;

	if &#40;pthread_attr_init&#40;&attr&#41;==-1&#41; &#123; 
		perror&#40;"main, pthread_attr_init"&#41;;
		exit&#40;EXIT_FAILURE&#41;;
	&#125;
	if &#40;pthread_attr_setdetachstate&#40;&attr, PTHREAD_CREATE_DETACHED&#41;==-1&#41; &#123;
		perror&#40;"main, pthread_attr_setdetachstate"&#41;;
		exit&#40;EXIT_FAILURE&#41;; 
	&#125; 
 
	for&#40;i=0;i<1000;i++&#41; &#123;
		startThread&#40;thread_function,NULL&#41;;
		fprintf&#40;stdout,"%d\n",i&#41;;
	&#125;

	/* Wait 500s to let the user inspect the example. */
	sleep&#40;500&#41;;

	if &#40;pthread_attr_destroy&#40;&attr&#41;==-1&#41; &#123;
		perror&#40;"main, pthread_attr_destroy"&#41;;
		exit&#40;EXIT_FAILURE&#41;;
	&#125; 
&#125;
Und das Makefile dazu:
Code:
.PHONY&#58; all clean

all&#58; thread
clean&#58;
	-rm thread *.o

thread&#58; thread.o
	$&#40;CC&#41; -lpthread -o $@ $^
Janka

_________________
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 02. Mär 2008 14:51 
Zitat:
"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.


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 02. Mär 2008 20:18 
Offline
Benutzeravatar

Registriert: 11. Feb 2006 19:10
Beiträge: 3569
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&#40;int s&#41;
&#123;
  STATIC int a;
  STATIC int b;

  if &#40;s&#41; &#123;
    a=12;
    b=34;
  &#125;

  printf&#40;"f1&#58; a&#58; %d, b&#58; %d\n",a,b&#41;;
&#125;

void f2&#40;int s&#41;
&#123;
  STATIC int a;
  STATIC int b;

  if &#40;s&#41; &#123;
    a=56;
    b=78;
  &#125;

  printf&#40;"f2&#58; a&#58; %d, b&#58; %d\n",a,b&#41;;
&#125;


int main&#40;void&#41;
&#123;
  f1&#40;1&#41;;
  f2&#40;1&#41;;
  f1&#40;0&#41;;
  f2&#40;0&#41;;
&#125;
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.


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 03. Mär 2008 13:24 
So, egal wie ich es mache, ob "static" in- oder außerhalb der Funktion, ich komme trotzdem nicht über 296 Threads hinaus...


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 03. Mär 2008 22:18 
Offline
Benutzeravatar

Registriert: 11. Feb 2006 19:10
Beiträge: 3569
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.


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 05. Mär 2008 11:04 
Ja, der Code ist mittlerwile exakt so drin, ohne jede Veränderung...


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 05. Mär 2008 16:42 
Offline
Benutzeravatar

Registriert: 11. Feb 2006 19:10
Beiträge: 3569
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.


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 06. Mär 2008 7:49 
Naja, ich habe eher bei dir ein Problem entdeckt:
Code:
if &#40;pthread_create&#40;thread,&attr,func,arg&#41;==-1&#41;
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.


Nach oben
   
 Betreff des Beitrags:
BeitragVerfasst: 07. Mär 2008 14:06 
Offline
Benutzeravatar

Registriert: 11. Feb 2006 19:10
Beiträge: 3569
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.


Nach oben
   
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen  Auf das Thema antworten  [ 21 Beiträge ]  Gehe zu Seite 1 2 Nächste

Alle Zeiten sind UTC+01:00


Wer ist online?

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


Sie dürfen keine neuen Themen in diesem Forum erstellen.
Sie dürfen keine Antworten zu Themen in diesem Forum erstellen.
Sie dürfen Ihre Beiträge in diesem Forum nicht ändern.
Sie dürfen Ihre Beiträge in diesem Forum nicht löschen.
Sie dürfen keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
Powered by phpBB® Forum Software © phpBB Limited
Deutsche Übersetzung durch phpBB.de