Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.
SP1 Klausur Programmieraufgabe
Hallo allerseits,
zur Vorbereitung auf die SP1-Klausur habe ich mich an die Programmieraufgabe der Klausur vom Juli 2012 gewagt. Das habe ich zusammengeschrieben. :
/* includes ... */
/*
**************
* Verwende Semaphor aus Uebung
**************
SEM *sem_init(int initVal);
int sem_del(SEM *sem);
void P(SEM *sem);
void V(SEM *sem);
*/
static void die(const char message[]) {
perror(message);
exit(EXIT_FAILURE);
}
// Makros, Funktionsdekl etc
typedef struct threadArg {
char * path;
int size;
} threadArg;
void *tstart(void* arg);
int getDirSize(char *path);
SEM * sem1;
// main
int main(int argc, char **argv) {
// Argumente auswerten, weitere Initialisierungen
if (argc < 3) {
fprintf(stderr, "falsche Anzahl Parameter");
exit(-1);
}
int n = argc - 2;
int nThreads = atoi(argv[1]);
sem1 = semCreate(nThreads);
pthread_t th [n];
threadArg * ret = malloc ( sizeof(threadArg) * n );
if (ret == NULL) {
die("malloc");
}
// Verz parallel bearbeiten
for (int i = 0; i < n; i++) {
ret[i].path = argv[i + 2];
if ( pthread_create(&th[i], NULL, &tstart, (void *) &ret[i]) != 0 ) {
die("pthread_create");
}
P(sem1);
pthread_detach(th[i]);
}
// Auf Terminierung der Threads warten, Ergebnis ausgeben
for (int i = 0; i < nThreads; i++) {
P(sem1);
}
for (int i = 0; i < n; i++) {
printf("Verzeichnisname: %s, Groesse: %i\n", ret[i].path, ret[i].size);
}
semDestroy(sem1);
free(ret);
}
// Thread-Funktion
void * tstart(void * arg) {
threadArg* targ = (threadArg *) arg;
targ->size = getDirSize(targ->path);
//V(sem2); // ??
V(sem1);
return arg;
}
int getDirSize (char * path) {
int sum = 0;
DIR * verz = opendir(path);
if (verz == NULL ) {
return -1;
}
struct dirent *entry;
while ( (entry = readdir(verz)) != NULL ) {
struct stat statBuf;
if (lstat (entry->d_name, &statBuf) != 0) {
return -1;
}
if (S_ISREG(statBuf.st_mode)) {
sum += statBuf.st_size;
} else if (S_ISDIR(statBuf.st_mode)) {
int e = getDirSize(entry->d_name);
if ( e != -1 ){
sum += e;
} else { // Fehler
return -1;
}
}
}
return sum;
}
Bin ich da zumindest konzeptionell auf dem richtigen Weg? Ganz richtig ist es wohl noch nicht.
Ich bin über jeden Hinweis und jeden Tipp sehr dankbar!
Liebe Grüße
- Wenn die Signaturen von Funktionen gegeben sind, solltest du sie nicht verändern. Also: [m]void *tstart(struct threadArg *)[/m], nicht [m]void *tstart(void *)[/m] um dir den Cast in [m]pthread_create(3)[/m] zu sparen.
- [m]static[/m] bei der Semaphore und den beiden Funktionen fehlt.
- Du prüfst die Beschränkung der Threadanazhl nicht. In der Angabe heißt es explizit nur Werte zwischen 1 und 399 sind erlaubt.
- Direkt nach dem Erstellen des Threads machst du [m]P(sem1);[/m]. Um die Anzahl der laufenden Threads passend zu limitieren müsstest du das aber vor dem starten des Threads tun.
- Die Aufgabenstellung sagt: “[…] das die Größe aller übergebenen Verzeichnisbäume parallel ermittelt und anschließend sortiert ausgibt.” (Hervorhebung durch mich). Mir scheint, hier braucht es noch einen Aufruf von [m]qsort(3)[/m] mit entsprechender Vergleichsfunktion. Wobei man natürlich trefflich streiten kann an dieser Stelle – denn wie sortiert sein sollte, steht hier nicht. In der Reihenfolge, in der die Verzeichnisse übergeben wurden?
- Die Fehlerbehandlung für [m]readdir(3)[/m] schaust du dir nochmal in den Übungsfolien an und packst sie auf deinen Spickzettel.
- Für das [m]lstat(2)[/m] musst du dir den passenden relativen Pfad innerhalb des Verzeichnisses erst aus Verzeichnisname und [m]entry->d_name[/m] geeignet zusammenbasteln. Gleiches gilt für den rekursiven Aufruf von [m]getDirSize()[/m].
Vielen Dank schon mal!
[quote=neverpanic] * Die Fehlerbehandlung für [m]readdir(3)[/m] schaust du dir nochmal in den Übungsfolien an und packst sie auf deinen Spickzettel.
[/quote]
Also:
errno = 0;
while ( (entry = readdir(verz)) != NULL ) {
…
errno = 0;
}
if (errno != 0) {
return -1;
}
Ist das richtig?
Liebe Grüße
Ja. Du kannst dann noch (falls im konkreten Fall gefordert) [m]perror(3)[/m] benutzen. Eine kürzere äquivalente Schreibweise ist übrigens
[code=c]while (errno = 0, (entry = readdir(dirp)) != NULL) {
// …
}
if (errno != 0) {
perror(„readdir“);
return -1;
}[/code]