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
folgendes:
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
ThreadInputBuffer.cpp
Vielen Dank schonmal!
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!