Unitat 3 · Sistemes Operatius (SO)
echo "Missatge enviat" > missatge.txt
Exercici
Implementeu un programa en C que simuli aquest comportament.
En un sistema operatiu multiprogramat o distribuït, diversos processos s’executen concurrentment i sovint necessiten intercanviar dades, sincronitzar accions o compartir recursos. Aquest intercanvi s’anomena Inter-Process Communication (IPC).
Com es pot transferir la informació entre processos? Recorda que els processos operen en espais d’adreçes independents. Per tant, no poden accedir a la mateixa informació.
Com es pot assegurar que dos processos no intentin accedir simultàniament a la mateixa informació? Imagina’t 2 processos executant una reserva en un avió i els dos processos assignen el mateix seient a dos passatgers diferents.
Com es poden coordinar els processos dependents entre si? Imagina’t un procés que genera dades i un altre procés que les processa. El procés que processa les dades necessita esperar a que el procés que les genera les hagi generat totes.
cat < missatge.txt | grep "e"Assumeix que un proces A vol imprimir un document:
Per fer-ho, implementem una cua d’impressió amb dos variables una que apunta al següent slot a imprimir (out) i una al següent slot lliure (in).

Les condicions de carrera es produeixen quan dos o més processos o fils d’execució intenten accedir simultàniament a recursos compartits o a dades sense la deguda sincronització.
Poden conduir a resultats inesperats o incorrectes en les operacions i a la inconsistència de les dades compartides.
Exclusió Mútua: Utilitzar mecanismes com semàfors, mutex o candaus per a garantir que només un procés pugui accedir als recursos compartits a la vegada.
Sincronització: Coordinar l’execució dels processos mitjançant sincronització de manera que no interfereixin entre ells quan accedeixen als recursos compartits.
La secció crítica és la part del codi on s’accedeix a recursos compartits. Per a evitar les condicions de carrera, els processos han de complir les següents condicions:

La comunicació entre processos a través dels sistemes de fitxers és una manera simple d’intercanviar informació entre ells. Això implica que dos o més processos acorden un fitxer pel seu nom i el utilitzen per a la comunicació. Un dels processos escriu al fitxer mentre que un altre processos llegeix el contingut del fitxer.
Persistència: Els fitxers són persistents, la informació roman en disc fins que s’elimina de forma explícita. Això no és òptim per a la comunicació efímera o temporal entre processos.
Problemes de Sincronització: Cal gestionar la sincronització de forma manual per garantir que un procés no llegeixi el fitxer abans que un altre procés hagi acabat d’escriure-hi. Aquesta sincronització pot ser complexa i pot conduir a errors si no es gestiona adequadament.
Eficiència: L’ús de fitxers per a la comunicació no és eficient en termes de rendiment, ja que involucra operacions d’entrada i sortida a disc, que són més lentes que altres mètodes de comunicació en memòria.
Un procés 1 (escriptor) escriu un missatge en un fitxer anomenat fitxer_comunicacio.txt.
Un procés 2 (lector) llegeix el missatge d’aquest fitxer i el mostra per pantalla.
Els pipes són dispositius lògics dissenyats per permetre la comunicació entre processos. Es comporten com una cua de caràcters amb una longitud fixa on els processos poden llegir o escriure.
En bash, podem utilitzar pipes per a comunicar dos processos. Per exemple, podem utilitzar el comandament echo per a enviar un missatge a través d’un pipe i el comandament cat per a llegir aquest missatge.
int pipe_fd[2];
pipe(pipe_fd);
if (fork() == 0) { // Fill (lector)
close(pipe_fd[1]);
char buffer[100];
read(pipe_fd[0], buffer, 100);
close(pipe_fd[0]);
printf("Missatge rebut: %s\n", buffer);
} else { // Pare (escriptor)
close(pipe_fd[0]);
write(pipe_fd[1],
"Missatge des de Process pare",
strlen("Missatge des de Process pare")
);
close(pipe_fd[1]);
}
mkfifo(char *name,mode_t mode);open(char *name, int flag);
Els FIFOs ofereixen una forma de comunicació més flexible entre processos amb l’avantatge afegit de poder ser utilitzats per processos que no comparteixen un antecessor comú.
mkfifo("fifo_example", 0666);
// Process 1 (escriptor)
int fd = open("fifo_example", O_WRONLY);
write(fd, "Missatge des de Process 1", strlen("Missatge des de Process 1"));
close(fd);
// Process 2 (lector)
int fd = open("fifo_example", O_RDONLY);
char buffer[100];
read(fd, buffer, 100);
close(fd);
printf("Missatge rebut: %s\n", buffer);
unlink("fifo_example");int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg): Envia un missatge msgp de mida msgz a la cua msgid.
ssize_t msgrcv(int msqid,void *msgp, size_t msgsz,long msgtyp,int msgflg): Rep un missatge de la cua msgid i el guarda a msgp.
struct message {
long msg_type;
char msg_text[100];
};
int main() {
key_t key = ftok("msg_queue_example", 65);
int msqid = msgget(key, 0666 | IPC_CREAT);
struct message msg;
msg.msg_type = 1;
strcpy(msg.msg_text, "Aquest és un missatge de prova!");
msgsnd(msqid, &msg, sizeof(msg), 0);
printf("Missatge enviat: %s\n", msg.msg_text);
return 0;
}Els sockets són eines fonamentals per a la comunicació entre processos a través d’una xarxa o dins del mateix ordinador. Poden utilitzar-se per a la comunicació mitjançant diferents protocols com TCP/IP o UDP.
Comunicació a través de la xarxa o local: Els sockets permeten la comunicació entre processos que poden estar en el mateix ordinador o en diferents ordinadors a través de la xarxa.
Adreces: Els sockets estan identificats per adreces, com les adreces IP per a la comunicació a través de xarxes o adreces locals per a comunicació dins del mateix ordinador.
Protocols: Els sockets poden utilitzar diferents protocols com TCP/IP o UDP, segons les necessitats de la comunicació.

int sockfd, new_sock;
struct sockaddr_in server_addr;
struct sockaddr_in new_addr;
socklen_t addr_size;
char buffer[100];
sockfd=socket(AF_INET, SOCK_STREAM, 0);
// Configuració de la connexió...
// Esperar connexions i llegir
new_sock = accept(sockfd,
(struct sockaddr*)&new_addr,
&addr_size);
recv(new_sock, buffer, 100, 0);
printf("Missatge rebut: %s\n", buffer);La comunicació mitjançant memòria compartida implica compartir una àrea de memòria entre diferents processos o fils d’execució d’un mateix procés. Aquest àrea de memòria és accessible per a tots els fils d’execució involucrats, permetent un accés directe i eficient a les dades compartides.
key_t key = ftok("fitxer_clau", 'R');
int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
char *shared_memory = (char *)shmat(shmid, (void *)0, 0);
// Escriure dades a la memòria compartida
strcpy(shared_memory, "Missatge a la memòria compartida");
// Llegir dades de la memòria compartida
printf("Missatge llegit: %s\n", shared_memory);
// Alliberar memòria compartida
shmdt((void *)shared_memory);
shmctl(shmid, IPC_RMID, NULL);pthread (POSIX Threads): És una interfície estàndard que facilita la creació i gestió de fils d’execució (threads) en C. Permet als processos tenir múltiples fils d’execució que comparteixen memòria i recursos.
OpenMP: És una API que facilita la programació paral·lela. Permet als desenvolupadors marcar parts del codi com a regions paral·leles, que s’executaran de forma concurrent en diferents fils d’execució.
La comunicació entre processos és essencial per a la coordinació i sincronització en sistemes operatius multiprogramats o distribuïts. Hi ha diversos mecanismes de comunicació, cadascun amb les seves pròpies característiques, avantatges i limitacions. La selecció del mecanisme adequat depèn de les necessitats específiques de l’aplicació, com la velocitat, la complexitat i l’escala de la comunicació requerida.


Unitat 3 · Sistemes Operatius (SO) 🏠