#include #include #include #include #include #include #include #include #include int lseek_test() { // apriamo in lettura il file https://github.com/marcotessarotto/exOpSys/blob/master/res/text01.txt // usiamo lseek per spostarci alla posizione 100 rispetto all'inizio del file // leggiamo un certo numero di caratteri char * filename = "text01.txt"; int fd; off_t current_file_offset; int res; fd = open(filename, O_RDWR); if (fd == -1) { perror("open()"); exit(1); } current_file_offset = lseek(fd, 0, SEEK_CUR); // ottengo il file offset corrente printf("offset corrente: %lu\n", current_file_offset); // mi aspetto 0 // ci spostiamo alla fine del file (l'ultimo byte del file) current_file_offset = lseek(fd, -1, SEEK_END); printf("offset corrente: %lu\n", current_file_offset); current_file_offset = lseek(fd, -100, SEEK_CUR); // ci spostiamo di 100 bytes indietro // rispetto alla fine del file printf("offset corrente: %lu\n\n", current_file_offset); // ci spostiamo di 100 byte rispetto all'inizio del file current_file_offset = lseek(fd, 100, SEEK_SET); int fd_copia; // file descriptor duplicato: condivide il file offset del file descriptor originale fd_copia = dup(fd); if (fd_copia == -1) { perror("dup()"); exit(1); } // scrivo il file offset di fd_copia e di fd (sarà lo stesso) printf("offset di fd_copia: %ld\n", lseek(fd_copia, 0, SEEK_CUR)); printf("offset di fd: %ld\n\n", lseek(fd, 0, SEEK_CUR)); current_file_offset = lseek(fd, 100, SEEK_SET); // superfluo, il file offset non cambia printf("(prima read) offset corrente: %lu\n", current_file_offset); char buffer[16+1] = { 0 }; res = read(fd, buffer, 16); // il file offset viene aggiornato automaticamente da read() e write() // il file offset viene spostato automaticamente in avanti di 16 bytes printf("read ha restituito %d bytes\nbuffer='%s'\n", res, buffer); current_file_offset = lseek(fd, 0, SEEK_CUR); // ottieni il file offset corrente printf("(dopo read) offset corrente: %lu\n\n",current_file_offset); // scrivo il file offset di fd_copia e di fd (sarà lo stesso) printf("offset di fd_copia: %ld\n", lseek(fd_copia, 0, SEEK_CUR)); printf("offset di fd: %ld\n\n", lseek(fd, 0, SEEK_CUR)); // if (0) { // utilizziamo lseek per aumentare la dimensione del file current_file_offset = lseek(fd, 100000, SEEK_END); printf("offset corrente: %lu\n", current_file_offset); memset(buffer, '!', 16); res = write (fd, buffer, 16); printf("write ha restituito %d bytes\n", res); printf("premi un tasto per continuare\n"); getchar(); } close(fd); } void esempio_fork_lseek() { // il processo padre apre un file (lo crea): OK // il processo padre crea un processo figlio: OK // il processo padre aspetta la conclusione del processo figlio: OK // il processo figlio scrive qualcosa sul file (aperto da entrambi i processi) e poi termina: OK // il processo padre, uscito da wait(), andrà a chiedere l'offset corrente del file aperto: OK char * filename = "prova.txt"; int fd; off_t current_file_offset; int res; fd = open(filename, O_CREAT| O_RDWR, S_IRUSR | S_IWUSR); if (fd == -1) { perror("open()"); exit(1); } int pid; char * msg; switch (pid = fork()) { case 0: // processo figlio msg = "hello world!"; res = write(fd, msg, strlen(msg)); // dovrei controllare l'esito di write if (res > 0) { printf("[child] offset di fd: %ld \n", lseek(fd, 0, SEEK_CUR)); } exit(0); break; case -1: break; default: // processo padre, viene restituito il PID del processo figlio res = wait(NULL); if (res == -1) { perror("wait()"); } printf("[parent] offset di fd: %ld \n", lseek(fd, 0, SEEK_CUR)); // modifica: // il processo padre va a leggere il "risultato" del processo figlio // leggendolo dal file condiviso // il processo padre "sa" che ci sono N bytes di risultato prodotto dal processo figlio // N è dato dalla differenza tra file offset finale e file offset iniziale // ESERCIZIO: completare e mostrare il risultato restituito dal processo figlio } } int incrementa_contatore() { int fd; char * filename = "contatore.txt"; int res; off_t offset; int contatore; // ipotesi: il file del contatore esiste già // QUINDI prima di lanciare il programma, creiamo a mano il file contatore.txt // con il comando: truncate -s 4 contatore.txt fd = open(filename, O_RDWR); if (fd == -1) { perror("open()"); exit(1); } // chiedo un "lucchetto" esclusivo sul file: // se un altro processo ha già acquisito il "lucchetto", il processo corrente // aspetterà fino a che l'altro processo non rilascia il "lucchetto" res = flock(fd, LOCK_EX); if (res == -1) { perror("flock()"); exit(1); } // leggere il valore del contatore dal file // lo incrementiamo // lo scriviamo nel file // il valore del contatore viene conservato nel file come "numero", non come stringa res = read(fd, &contatore, sizeof(contatore)); // read sposta automaticamente il file offset in avanti (se ha successo) if (res == -1) { perror("read()"); exit(1); } else if (res < 0) { printf("problema! ho letto meno di 4 bytes\n"); exit(1); } contatore++; // scrivo il valore aggiornato nel file: // per prima cosa, riposiziono il file offset alla posizione 0 offset = lseek(fd, 0, SEEK_SET); if (offset == -1) { perror("lseek()"); exit(1); } res = write(fd, &contatore, sizeof(contatore)); if (res == -1) { perror("write()"); exit(1); } else if (res < 0) { printf("problema! ho scritto meno di 4 bytes\n"); exit(1); } // rilascia il lucchetto acquisito sopra // se l'altro processo è in attesa, dopo questo flock potrà procedere res = flock(fd, LOCK_UN); if (res == -1) { perror("flock()"); exit(1); } if (close(fd) == -1) { perror("close"); } return contatore; } int main(int argc, char * argv[]) { int counter_value; // problema: // come creo il file contatore.txt, che contenga il valore intero 0? // truncate -s 4 contatore.txt for (int i = 0; i < 10000000; i++) { counter_value = incrementa_contatore(); } printf("counter_value = %d\n", counter_value); return 0; }