für jeden Thread einen Ausgabe Stream



  • Hallo

    Ich habe folgendes vor.

    Ein C Programm unter linux das in jedem Thread ausgaben macht.
    Damit diese nicht gemischt werden und ich mir das synchronisieren spare, verwendet jeder Thread eine eigene Datei um die Ausgaben weg zu schreiben.
    Also gibt es eine Struktur in der für jeden Thread ein Filediscriptor steht.
    Zugegriffen wird über die PID als Index.

    typedef struct _threadFD_s
    {
      pid_t pid;
      FILE *stream
    } threadFD_s;
    
    ....
    
    threadFD_s threads[MAX_THREADS];
    
    ....
    
    void initFD()
    {
      int i;
      for ( i=0; i<MAX_THREADS; i++)
      {
        threads[i].pid=0;
        threads[i].stream=NULL;
      }
    }
    
    void deInitFD()
    {
      int i;
      for ( i=0; i<MAX_THREADS; i++)
      {
        if (threads[i].stream != NULL)
          fclose(threads[i].stream);
      }
    }
    
    FILE *findFDviaPID(pid_t pid)
    {
      int i;
      char tmp[255];
      for ( i=0; i<MAX_THREADS; i++)
      {
        if (threads[i].pid == pid)
          return threads[i].stream;
      }
      // if reached no stream for pid was found.
      // open new stream and add to struct
    
      for ( i=0; i<MAX_THREADS; i++)
      {
        if (threads[i].pid == 0)
          break; // find first free slot.
      }
      snprintf(tmp, "/tmp/output.%d", sizeof(tmp), pid);
      threads[i].stream = fopen( tmp, "w" );
      threads[i].pid = pid;
      return threads[i].stream;
    }
    

    Code ist frei aus dem Gedächtnis geschrieben und soll eigentlich nur das Prinzip verdeutlichen.

    Schöner wäre es wenn ich einfach eine Variable habe die für jeden Thread einzeln global wäre.
    Wie kann ich das besser und vor allem performanter lösen?



  • Könnte TLS die Antwort sein?
    http://stackoverflow.com/questions/5450694/thread-local-storage-overhead

    __thread FILE *stream;
    

    Soll zwar langsam sein aber ich glaube das teste ich mal.


  • Mod

    Wenn du die glibc benutzt (unter Linux wirst das in der Regel der Fall sein), sollten die höheren Ausgabefunktionen wie printf schon threadsicher sein. Das heißt, ein

    printf("Ich bin Thread %d und hier ist meine Ausgabe\n", thread_number);
    

    Wird garantiert immer an einem Stück ausgegeben und du bekommst niemals so etwas wie

    Ich bin Thread 3 und hiIch bin Thread 4 und hier ist meine Ausgabe
    er ist meine Ausgabe
    


  • Oh danke SeppJ

    Leider nutze ich die uclibc und ich bin mir nicht sicher ob es dort auch der Fall ist.
    Außerdem wäre das dann ein deutlicher Flaschenhals wenn die Threads z.B. auf stdout schreiben würden.

    Ich gebe zu das ich die Ausgaben nicht direkt ausgeben will sondern in einen Buffer schreiben will. Von daher bringt es mir nichts wenn fprintf threadsave ist.


  • Mod

    decembersoul schrieb:

    Leider nutze ich die uclibc und ich bin mir nicht sicher ob es dort auch der Fall ist.

    Das ist bestimmt dokumentiert

    Außerdem wäre das dann ein deutlicher Flaschenhals wenn die Threads z.B. auf stdout schreiben würden.

    Die Threadsicherheit gilt natürlich auch für fprintf&Co.

    Ich gebe zu das ich die Ausgaben nicht direkt ausgeben will sondern in einen Buffer schreiben will. Von daher bringt es mir nichts wenn fprintf threadsave ist.

    Dann sag das doch gleich, anstatt uns in die Irre zu führen. Wenn das am Ende ein gemeinsamer Buffer für alle Threads sein soll, sicher ihn doch einfach durch einen Mutex ab.

    Beschreib mal dein Ziel, nicht was du denkst, was eine technische Umsetzung wäre.



  • Ich hatte versucht das Problem vereinfacht da zu stellen. Ging wohl nach hinten los.

    Ok es geht um einen loging Mechanismus.

    Dabei soll die Log Message nicht direkt ausgegeben werden sondern erst in einem Buffer landen. Wenn ich nun aber anfange alle Log Messages von allen Threads in EINEN Buffer ab zu legen, dann muss ich wirklich es mit Mutexen schützen.
    Dann hätte ich einen Falschenhals weil alle X Threads auf eine Variable zugreifen.
    Das will ich nicht. Daher soll jeder Thread einen eigenen Buffer bekommen.
    Das es später nicht mehr möglich ist diese in perfekter syncronisation aus zu geben ist dabei nicht so wichtig.
    Jeder Thread schreibt also in seinen eigenen Buffer.
    Jeder Thread hat dann einen Fkt printBufferToStdout oder so.

    Dazu muss aber jeder Thread eine Unterschoedliche Instanz des Buffers haben.

    __thread char *buffer[MAX_MESSAGES][MAX_MESSAGE_LENGTH];
    

    Nun brauche ich natürlich noch einen counter das mit eine Art Ringbuffer realisiert.

    __thread int bufferpos;
    
    void log(const char* fmt, ...)
    {
      va_list ap;
      va_start(ap, fmt); /* Initialize the va_list */
      vsnprintf(buffer[bufferpos++], MAX_MESSAGE_LENGTH, fmt, ap);
    
      if ( bufferpos >= MAX_MESSAGES ) 
        bufferpos= 0;
      va_end(ap); /* Cleanup the va_list */
    }
    

    Da ich auf die Fkt immer nur aus einem Thread zugreife, brauche ich den Zugriff auf buffer und bufferpos nicht schützen. (so stelle ich mir das zumindest vor)

    Passt das so?


  • Mod

    Sieht prinzipiell richtig aus (Zeig doch mal ein ganzes Beispiel. Wenn ich mir alles was fehlt richtig dazu denke, ist das Ergebnis natürlich richtig.), aber wozu ist das gut? Du überschreibst ja einfach deine Nachrichten und bekommst sie nie zu sehen. 😕



  • Das siehst Du richtig.
    Die Nachrichten sollen in einem Buffer vorgehalten werden und bei Bedarf zur Analyse ausgegeben werden.
    Also z.B. die letzten 100 Log Messages.

    Ist eine Art CallTrace mit erweiterten Ausgaben.

    void printLog()
    {
    ....
    }
    

    Gibt es natürlich auch noch.

    Die

    __thread char *buffer[MAX_MESSAGES][MAX_MESSAGE_LENGTH];
    

    ist aber nur eine gcc Erweiterung oder? Also kein ANSI.
    Wie würde man es denn ANSI Conform machen?


  • Mod

    Ist C11 erlaubt?



  • Kann ich nicht genau sagen. Glaube aber nicht. Wäre viel zu neu.
    Was gäbe es da denn so schönes?


  • Mod

    decembersoul schrieb:

    Kann ich nicht genau sagen. Glaube aber nicht. Wäre viel zu neu.
    Was gäbe es da denn so schönes?

    Threadsupport 🙂 .



  • Nativ Threadsupport mit TLS?
    ok, ich glaube ich bleibe bei pThread


Anmelden zum Antworten