C++ Initialisierung eines structs in der Implementierungsdatei cpp

|silent

Newbie
Registriert
Nov. 2009
Beiträge
3
Guten Abend,

da ich gerade vergebens auf der Suche nach einer - auch nur annähernden - Lösung für mein Problem war, wende ich mich nun an die Experten aus dem Forum.

Kurz zum Sachverhalt: Ich habe einen Puffer geschrieben, der mir Dateien von der Platte einliest. Damit das schneller geht, kommt das ganze in einen eigenen Thread, der dann schön parallel (zu den seriellen Aufrufen aus einer anderen Bibliothek) arbeitet. Soweit so gut.

Damit ich mit Threads arbeiten kann, brauche ich gemeinsame und damit statische Speicherbereiche - so wünsche ich mir zumindest die Lösung.

Ich habe dazu ein Header- und ein Implementierungsfile erstellt.

Der Compiler liefert mir bei Compilierung mit

Code:
g++ -D_REENTRANT ThreadInputBuffer.cpp -lpthread

folgendes:

Code:
    ubuntu@ubuntu:~/Compiler/Buffer$ g++ -D_REENTRANT ThreadInputBuffer.cpp -lpthread
    /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
    (.text+0x18): undefined reference to `main'
    /tmp/ccASrWca.o: In function `ThreadInputBuffer::initBuffer()':
    ThreadInputBuffer.cpp:(.text+0x19): undefined reference to `ThreadInputBuffer::buffer'
    /tmp/ccASrWca.o: In function `ThreadInputBuffer::fillBuffer(void*)':
    ThreadInputBuffer.cpp:(.text+0x139): undefined reference to `ThreadInputBuffer::buffer'
    ThreadInputBuffer.cpp:(.text+0x1b4): undefined reference to `ThreadInputBuffer::buffer'
    /tmp/ccASrWca.o: In function `ThreadInputBuffer::~ThreadInputBuffer()':
    ThreadInputBuffer.cpp:(.text+0x2b0): undefined reference to `ThreadInputBuffer::buffer'
    /tmp/ccASrWca.o: In function `ThreadInputBuffer::getChar()':
    ThreadInputBuffer.cpp:(.text+0x401): undefined reference to `ThreadInputBuffer::buffer'
    collect2: ld gab 1 als Ende-Status zurück

Da bereits vorher genau die selben Fehler auch bei den statisch definierten Variablen wie workerBufferSlot und workerBufferOffset kamen, denke ich, dass der Fehler definitiv bei der Initialisierung des Structs liegen muss. Aber wie kann ich mein selbst definiertes Struct initialisieren, wenn ich erst vorm Compilieren mit dem Präprozessor drüberlaufe und mir die Größe des Feldes definiere?

ThreadInputBuffer.h
PHP:
    #ifndef IINPUTBUFFER_H_
    #define IINPUTBUFFER_H_
     
    #include "../config.h"
     
    #include <stdio.h>
    #include <pthread.h>
     
    #include "Buffer.h"
     
    class ThreadInputBuffer: public IBuffer {
    public:
      static struct inputBuffer {
        char slot[IB_MAX_SLOTS][IB_SLOT_SIZE];
      } *buffer;
     
      pthread_t threadWorker;
     
      int argDummy; // dummy für den Aufruf der Threads ohne Argumente
     
      static int fdInputFile;
     
      int activeBufferSlot; // bei Berechnungen kann auch -1 werden
      int activeBufferOffset;
      unsigned int activeBufferPosition;
      bool activeBufferSteppedBack;
     
      static int workerBufferSlot;
      static int workerBufferOffset;
     
      void initBuffer();
      static void *fillBuffer(void* arg);
     
      ThreadInputBuffer(const char* inputFile);
      virtual ~ThreadInputBuffer();
     
      char getChar();
      void ungetChar(unsigned int steps);
    };
     
    #endif /* INPUTBUFFER_H_ */

ThreadInputBuffer.cpp
PHP:
    #include "ThreadInputBuffer.h"
     
    #include <stdio.h>  // fprintf
    #include <stdlib.h> // posix_memalign, exit
    #include <string.h> // memset
    #include <fcntl.h>  // open
    #include <unistd.h> // lseek, read, write, pread, close
     
    int ThreadInputBuffer::fdInputFile = 0;
    int ThreadInputBuffer::workerBufferSlot = 0;
    int ThreadInputBuffer::workerBufferOffset = 0;
     
    void ThreadInputBuffer::initBuffer() {
      if (posix_memalign(reinterpret_cast<void **>(&buffer), IB_SLOT_SIZE, sizeof(*buffer)) != 0) {
        close(fdInputFile);
        fprintf(stderr, "Error: can't initialize InputBuffer because of bad_alloc!\n");
        exit(-1); // Buffer beenden, da Buffer nicht im Speicher ausgerichtet werden kann
      }
     
      activeBufferSlot = 0; // Slot, der gerade genutzt wird
      activeBufferOffset = 0; // Totaler Offset seit Eingabedatei Anfang
      activeBufferPosition = 0; // Relativer Offset im aktuellen Slot
      activeBufferSteppedBack = false;
     
      argDummy = 0;
      // lese den ersten Slot ein
      workerBufferSlot = 0;
      workerBufferOffset = 0;
     
      pthread_create(&threadWorker, NULL, fillBuffer, &argDummy);
      pthread_join(threadWorker, NULL); // warte bis fertig (seriell)
     
      // lese nun den zweiten Slot - parallel zum Programmlauf - ein
      workerBufferSlot = 1;
      workerBufferOffset = IB_SLOT_SIZE;
     
      pthread_create(&threadWorker, NULL, fillBuffer, &argDummy); // parallel
    }
     
    void *ThreadInputBuffer::fillBuffer(void *arg) {
      int charsInCurrentBuffer = pread(fdInputFile,
                                       &buffer->slot[workerBufferSlot],
                                       IB_SLOT_SIZE,
                                       workerBufferOffset * IB_SLOT_SIZE);
     
      if (charsInCurrentBuffer != IB_SLOT_SIZE) {
        if (charsInCurrentBuffer == -1) {
          fprintf(stderr, "Error: cant't fill current buffer!\n");
          exit(-1); // Buffer beenden, da der Buffer mit keinem Zeichen gefüllt werden konnte.
        } else {
          // EOF und Position bekannt, im currBuffer abspeichern, spart Zeit bei getChar()
          memset(&buffer->slot[workerBufferSlot][charsInCurrentBuffer], '\0', IB_SLOT_SIZE - charsInCurrentBuffer);
        }
      }
    }
     
    ThreadInputBuffer::ThreadInputBuffer(const char* inputFile) {
      fdInputFile = open(inputFile, O_RDONLY | O_DIRECT, 0666);
     
      if (fdInputFile == -1) {
        fprintf(stderr, "Error: Can't open input file!\n");
        exit(-1); // Buffer beenden, da Datei nicht geöffnet werden kann
      }
     
      initBuffer();
    }
     
    ThreadInputBuffer::~ThreadInputBuffer() {
      pthread_join(threadWorker, NULL); // warte bis der workerThread fertig ist
      close(fdInputFile);
      free(buffer);
    }
     
     
    char ThreadInputBuffer::getChar() {
      if (activeBufferPosition == IB_SLOT_SIZE) {
        activeBufferSlot = (activeBufferSlot + 1) % IB_MAX_SLOTS;
        activeBufferPosition = 0;
        activeBufferOffset++;
     
        if (!activeBufferSteppedBack) {
          pthread_join(threadWorker, NULL); // warte bis der workerThread mit benötigtem Slot fertig ist
     
          // invariante: ab dieser Stelle ist der aktuelle Bufferslot + 1 bereits gefüllt!
          // fülle deshalb gleich den Nächsten
          workerBufferSlot = (activeBufferSlot + 1) % IB_MAX_SLOTS;
          workerBufferOffset = activeBufferOffset + IB_SLOT_SIZE;
     
          pthread_create(&threadWorker, NULL, fillBuffer, &argDummy);
        } else {
          activeBufferSteppedBack = false;
        }
      }
     
      return buffer->slot[activeBufferSlot][activeBufferPosition++];
    }
     
    void ThreadInputBuffer::ungetChar(unsigned int steps) {
      if (activeBufferPosition >= steps) {
        // bleibe im aktuellen Slot
        activeBufferPosition -= steps;
      } else {
        // springe einen Slot zurück
        if (activeBufferOffset == 1) {
          fprintf(stderr, "Error: can't go back any more!\n");
          exit(-1); // Buffer beenden, da am Anfang der Eingabedatei angekommen
        }
     
        activeBufferSlot = (activeBufferSlot - 1) % IB_MAX_SLOTS;
        activeBufferPosition = IB_SLOT_SIZE - (steps - activeBufferPosition);
        activeBufferOffset--;
        activeBufferSteppedBack = true;
      }
    }

Vielen Dank schonmal!
 
Compiliere mal mit "-g", damit du Zeilennummern siehst.
Und du willst doch ein Object file machen, oder? Wenn ja, dann "-c $Objectfilename".
Außerdem hast du beim Linken offensichtlich nicht die Datei mit der main() angegeben.
Vielleicht einfach Kompilier- und Linkphase vergessen zu trennen?
Und dann nochmal gescheit formulieren, was eigentlich dein Problem ist? :)
 
Dein statisches buffer-Member muß genau wie die anderen statischen Member in der .cpp-Datei initialisiert werden. Also

Code:
ThreadInputBuffer::inputBuffer* ThreadInputBuffer::buffer = 0;
 
Hey, danke! Das funktioniert. Ich konnte nun alles compilieren und linken - hätte wohl doch eine Pause einlegen sollen ;)

Code:
    ubuntu@ubuntu:~/Compiler/Buffer$ make -f ThreadMakefile
    g++ -c -g -D_REENTRANT ThreadInputBuffer.cpp -pthread -o IBuffer.o
    g++ -c -g ThreadOutputBuffer.cpp -o OBuffer.o
    g++ -c -g ThreadBuffer.cpp -o Buffer.o 
    g++ -shared -o libBuffer.so IBuffer.o OBuffer.o Buffer.o

Allerdings habe ich nun ein Problem beim Ausführen meines Programms (parserx):

Code:
./parserx: symbol lookup error: lib/libBuffer.so: undefined symbol: pthread_create

Die Suchmaschine meines Vertrauens konnte mir nichts passendes liefern, hatte vielleicht schon mal jemand ein ähnliches Problem oder weiß was hier fehlt?

Vielen Dank schonmal!
 
Vllt irgendwas nicht mit -pthread gebaut?
Außerdem solltest du dringend Warnings anmachen, mindestens -Wall. Besser noch -pedantic und -ansi.
 
Danke, das hat geklappt. Ich hatte vergessen das Ganze auch in der darüberliegenden Klasse mit -pthread zu compilieren. Nun hat es geklappt.

Vielen Dank für die schnellen Antworten!
 
Btw, registriert seit November 2009 und nur 3 Beiträge? Machst deinem Namen alle Ehre. ;)
 
Zurück
Oben