Recursos:
Per disposar dels manuals de les crides de sistema POSIX podeu instal·lar:
$ sudo apt-get install manpages-posix
La majoria de crides de sistema estan al paquet manpages-dev:
$ sudo apt-get install manpages-dev
Si teniu dubtes de quin paquet es necessita per tenir cert manual podeu utilitzar la comanda dpkg i el fet de saber que els manuals es troben a:
/usr/share/man/manx
On x és la secció del manual. Sabem (o podeu consultar al manual de man - $ man man) que les crides de sistema estan a la secció 2. Per tant si volem saber qui ens proporciona el manual de fork:
$ dpkg -S /usr/share/man/man2/fork.2.gz manpages-dev: /usr/share/man/man2/fork.2.gz
Més sobre manuals de Linux a Manuals de Linux/Unix.
Hi han tres descriptors de fitxer per defecte:
Aquests descriptors de fitxers es troben definits al fitxer unistd.h:
$ cat /usr/include/unistd.h
#define STDIN_FILENO 0 /* Standard input. */ #define STDOUT_FILENO 1 /* Standard output. */ #define STDERR_FILENO 2 /* Standard error output. */
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
Obre el fitxer de nom pathname per lectura, escritura o lectura/escritura (segons flags). Retorna el descriptor de fitxer (enter positiu).
int creat(const char *pathname, mode_t mode);
Crea un fitxer buït per escriure. mode defineix els drets d’accès.
ssize_t read(int fd, void *buf, size_t count);
Intenta llegir count bytes i els posa en la variable buf. Retorna el nombre de bytes llegits.
ssize_t write(int fd, const void *buf, size_t count);
Escriu count bytes de la variable buf. Retorna el nombre de bytes escrits.
Exemples:
Exemple 1
#include <unistd.h> /* biblioteca UNIX estandard */ ... write(STDERR_FILENO,"fitxer no existent\n",19);
Exemple 2:
#include<stdio.h> #include<fcntl.h> main() { char *p = \"hello world\\n\"; int fp; fp = open(\"hello.c\",O_CREAT,0666); write(fp,p,11); }
Exemple 3:
/* program to read a list of floats from a binary file */ /* first byte of file is an integer saying how many */ /* floats in file. Floats follow after it, File name got from */ /* command line */ #include<stdio.h> #include<fcntl.h> float bigbuff[1000]; main(int argc, char **argv) { int fd; int bytes_read; int file_length; if ( (fd = open(argv[1],O_RDONLY)) = -1) { /* error file not open */.... perror("Datafile"); exit(1); } if ( (bytes_read = read(fd,&file_length,sizeof(int))) == -1) { /* error reading file */... exit(1); } if ( file_length > 999 ) {/* file too big */ ....} if ( (bytes_read = read(fd,bigbuff,file_length*sizeof(float))) == -1) { /* error reading open */... exit(1); } }
On la constant STDERR_FILENO es refereix a la sortida estàndard d'error (valor 2) definida al fitxer unistd.h:
$ cat /usr/include/unistd.h ... /* Standard file descriptors. */ #define STDIN_FILENO 0 /* Standard input. */ #define STDOUT_FILENO 1 /* Standard output. */ #define STDERR_FILENO 2 /* Standard error output. */
int close(int fd);
Tanca el fitxer.
off_t lseek(int fildes, off_t offset, int whence);
Mou el posicionament del fitxer a una nova localització resultant d’afegir offset a una base. La base pot ser l’inici del fitxer, la localització actual del fitxer, o la mida del fitxer, sd’acord al que indiqui whence.
int unlink(const char *pathname);
Esborra el fitxer.
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h>
int stat(const char *path, struct stat *buf); int fstat(int filedes, struct stat *buf); int lstat(const char *path, struct stat *buf);
Podeu descarregar tots els exemples d'aquest apartat aquí.
Descàrrega: copia.c.
El codi font del programa copiar (que trobareu a la carpeta exempleFitxers) és:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <assert.h> #define MIDA_BUFFER 50 int main (int argc, char **argv) { int f1, f2; int quants, escrits; char buf[MIDA_BUFFER]; int estat; estat = EXIT_SUCCESS; if (argc==3) { f1=open(argv[1],O_RDONLY); f2=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666); if (f1==-1) { estat=EXIT_FAILURE; write(STDERR_FILENO,"fitxer no existent\n",19); } if (f2==-1) { estat=EXIT_FAILURE; write(STDERR_FILENO,"Problemes amb el fitxer destí\n",31); } } else { estat=EXIT_FAILURE; write(STDERR_FILENO,"Arguments incorrectes\n",22); } if (estat==0) { quants=read(f1,buf,MIDA_BUFFER); while(quants>0){ escrits=write(f2,buf,quants); quants=read(f1,buf,MIDA_BUFFER); } } close(f1); close(f2); return estat; }
Podem compilar amb:
$ gcc -o copia copia.c
Ara podeu executar la comanda copia de la següent forma:
./copia copia.c copia_de_la_comanda.c
Podeu escollir el nom que vulgueu per al fitxer copia_de_la_comanda.c.
O primer preparant el PATH:
$ PATH=$PATH":."
i aleshores executar:
$ copia copia.c copia_de_la_comanda.c
Interpretació del codi:
Includes:
$ man 2 open
NOTA: Consulteu l'apartat Manuals (man) si no teniu els manuals de les crides de sistema.
Tal com podem veure executant:
$ man man ........... The table below shows the section numbers of the manual followed by the types of pages they contain. 1 Executable programs or shell commands 2 System calls (functions provided by the kernel) 3 Library calls (functions within program libraries) 4 Special files (usually found in /dev) .........................
L'opció 2 ens mostra les crides al sistema.
Tornant al man del open, l'apartat SYNOPSIS:
SINOPSIS #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
Ens mostra quins han de ser els includes per poder utilitzar aquesta funció. Si tenim curiositat per saber on estan aquests includes en el nostra sistema podem executar les següents comandes:
$ sudo updatedb $ locate fcntl.h .......... /usr/include/fcntl.h
Si voleu saber quin paquet ens proporciona aquest paquet podeu utilitzar:
$ dpkg -S /usr/include/fcntl.h libc6-dev: /usr/include/fcntl.h
Com podeu veure el paquet és libc6-dev.
Podeu trobar informació més exhaustiva de totes les senyals executant:
$ man kill
Consulteu la comanda kill a l'article Processos Linux.
Recursos:
int kill(pid_t pid, int sig);
Envia el senyal sig al procés pid
int raise(int sig);
Equivalent a kill(getpid(), sig); envia el senyal sig al propi procés
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler); Si el procés rep el senyal signum s’executarà la funció handler. Si ha anat bé retornarà l’apuntador a la funció handler o -1 si hi ha error (errno). La funció handler la pot definir l’usuari. Es disposen de dues predefinides: SID_DFL() (acaba el procés) i SIG_IGN() (ignora el senyal)
int sigaction(int s, const struct sigaction *act, struct sigaction *oldact);
int sigpending(sigset_t *set); retorna el conjunt de senyals pendents. (Les bloquejades).
Canvia l’acció a fer (act) en el cas de rebre el senyal s
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
Canvia el conjunt de senyals bloquejades. how indica el comportament de l’acció: SIG_BLOCK unió del conjunt actual amb set, SIG_UNBLOCK els senyals en set s’eliminen del conjunt actual, SIG_SETMASK el conjunt de senyals a bloquejar és l’argument set.
int unsigned int alarm(unsigned int seconds); Útil per implementar timers.
Si creem un script bash com el següent:
$ gedit prova.sh
function accio1 { echo "Senyal 1 rebut (SIGHUP)" } trap accio1 1 while true do sleep 5 echo "." done
I l'executem amb
$ bash prova.sh & [1] 13429
El nombre que ens torna és l'identificador del procés o PID (podrieu consultar el PID també amb ps aux). Aquest bash com veureu, mostra per la sortida estàndard un punt cada 5 segons.
$ kill -1 13429 Senyal 1 rebut (SIGHUP)
Fixeu-vos que kill no sempre mata un procés. En aquest cas el procés captura un senyal i mostra el missatge. Aquest senyal (el senyal 1) com hem vist a la taula de senyals no acaba el procés.
Si volem que el procés finalitzi pode utilitzar un script bash com el següent:
function accio1 { echo "Senyal 1 rebut (SIGHUP)" echo "Tanquem els fitxers si en tenim." exit } trap accio1 1 while true do sleep 5 echo "." done
Si executem:
$ bash prova & [1] 13452 kill -1 13452
Si que finalitzarà el procés per que li diem explícitament amb la comanda exit.
En canvi si utilitzem el senyal 9 en un script com el següent:
function accio9 { echo "Senyal 1 rebut (SIGHUP)" echo "Tanquem els fitxers si en tenim." exit } trap accio9 9 while true do sleep 5 echo "." done
I executem
$ bash prova & [1] 13455 kill -9 13455
Matarà el procés.
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <signal.h> int main( int argc, char∗ argv [ ] ) { printf( "Hola\n" ) ; pid_t my_pid = getpid ( ) ; / ∗ Obtinc el meu identificador de procés ∗ / kill(my_pid, SIGSTOP) ; / ∗ Em suicido ∗ / printf( "Segueixo existint?\n" ) ; }
Podeu descarregar l'exemple aquí.
#include <stdio.h> /* biblioteca d'E/S estandard */ #include <unistd.h> /* biblioteca UNIX estandard */ #include <signal.h> /* biblioteca d'ús de senyals */ /* gestor del senyal INT (Interrupció des del terminal)*/ void copsaINT(int sig_num) { signal(SIGINT, copsaINT);/* refem l'associació del senyal al gestor. Si no es fa, el següent cop que es faci ctrl-c, no passarà per aquí */ printf("Ei! No facis això!!!\n"); fflush(stdout); } int main(int argc, char* argv[]) { signal(SIGINT, copsaINT);/* Associació el senyal INT al gestor copsa_int */ while (1) {pause();} /* Iteració de durada infinita */ }
Podeu descarregar l'exemple aquí
#include <stdio.h> #include <unistd.h> #include <signal.h> char usuari[40]; /* buffer per guardar el nom d'usuari */ void copsaAlarma(int sig_num) { /* definim un gestor pel senyal d'alarma. */ printf("Temps esgotat. Sortint...\n\n"); exit(0); } int main(int argc, char* argv[]) { signal(SIGALRM, copsaAlarma);/* associa el gestor per senyals ALRM */ printf("Nom usuari: "); /* demanem l'usuari */ fflush(stdout); alarm(10); /* Comen a una alarma de 10 segons */ gets(usuari); /* Obtenim usuari */ alarm(0); /* Eliminem el timer */ printf("Nom usuari: '%s'\n", usuari); return 0; }
Podeu descarregar l'exemple aquí
Fitxer parlo.c :
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct my_msgbuf { long mtype; char mtext[200]; }; int main(void) { struct my_msgbuf buf; int msqid; key_t key; if ((key = ftok("recull", 'B')) == -1) { perror("ftok"); exit(1); } if ((msqid = msgget(key, 0644 | IPC_CREAT)) == -1) { perror("msgget"); exit(1); } printf("Entra linees de text, ^D per sortir:\n"); buf.mtype = 1; /* no cal en aquest cas */ fgets(buf.mtext,200,stdin); while( !feof(stdin)) { if (msgsnd(msqid, (struct msgbuf *)&buf, sizeof(buf), 0) == -1) perror("msgsnd"); fgets(buf.mtext,200,stdin); } if (msgctl(msqid, IPC_RMID, NULL) == -1) { perror("msgctl"); exit(1); }
return 0; }
Fitxer escolto.c:
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct my_msgbuf { long mtype; char mtext[200]; }; int main(void) { struct my_msgbuf buf; int msqid; key_t key; if ((key = ftok("recull", 'B')) == -1) { perror("ftok"); exit(1); } if ((msqid = msgget(key, 0644)) == -1) { /* connecta a la cua */ perror("msgget"); exit(1); } printf("escolto: preparat per rebre missatges, capità.\n"); while (true) { /* escolto mai s'atura! */ if (msgrcv(msqid, (struct msgbuf *)&buf, sizeof(buf), 0, 0) == -1) { perror("msgrcv"); exit(1); } printf("escolto: \"%s\"\n", buf.mtext); } return 0; }
pid_t fork(void);
Recursos:
Fork bomb és una tipus d'atac de denegació de serveis que permet saturar una màquina a base de crear il·limitats processos fills amb la comada fork. Veieu la comanda ulimit.
int dup(int oldfd); int dup2(int oldfd, int newfd);
Duplica un descriptor de fitxer. Permet crear descriptors de fitxers a partir de descriptors ja existents. Exemple:
int main(int argc, char argv[]) { int f1, f2, f3; ... f1=open("fitxer1", O_RDONLY); f2=open("fitxer2", O_RDONLY); f3=dup(f1);
Recursos:
SYNOPSIS #include <unistd.h> int pipe(int filedes[2]); DESCRIPTION pipe() creates a pair of file descriptors, pointing to a pipe inode, and places them in the array pointed to by filedes. filedes[0] is for reading, filedes[1] is for writing.
La crida pipe crea un vector amb dos descriptors de fitxer: un de lectura i un d'escriptura.
Recursos:
int msgctl(int msqid, int cmd, struct msqid_ds ∗buf);
key_t ftok(const char ∗pathname, int proj_id);
Genera una clau a partir d’un nom de fitxer existent i un enter de 8 bits. Aquesta clau serveix com a identificador per elements del sistema V.
int msgget(key_t key, int msgflg);
Connecta a una cua existent (msgflg només conté les proteccions) o crea una cua (IPC_CREAT | proteccions). Retorna l’identificador de cua a usar.
int msgsnd(int msqid, const void ∗msgp, size_t msgsz, int msgflg);
Envia el missatge que hi ha a msgp a la cua msqid.
ssize_t msgrcv(int msqid, void ∗msgp, size_t msgsz, long msgtyp, int msgflg);
Elimina el primer missatge de cua msqid i el posa a msgp.
sem_init(sem_t ∗sem, int pshared, unsigned int value);
Sem apunta a un semàform pshared indica si serà o no serà compartit amb altres processos i, value és el valor inicial del semàfor.
sem_wait(sem_t ∗sem);
Si sem és < 0, el procés que l’ha cridat es bloqueja fins que un altre procés cridi sem_post.
sem_post(sem_t ∗sem);
Incrementa el semàfor i desperta, si n’hi ha, qualsevol procés que esperi el semàfor.
sem_getvalue(sem_t ∗sem, int ∗valp);
Valor del semàfor.
sem_destroy(sem_t ∗sem); Destrucció del semàfor
#include <pthread.h> #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #define NITER 1000000 int comptador = 0; sem_t mutex; void * filSuma(void * a) { int i, tmp; for(i = 0; i < NITER; i++) { sem_wait (&mutex); tmp = comptador; /* copia el comptador global a un de local */ tmp = tmp+1; /* incrementa la copia local */ comptador = tmp; /* guarda el valor local al comptador global*/ sem_post (&mutex); } } int main(int argc, char * argv[]) { pthread_t tid1, tid2; sem_init(&mutex, 0, 1); if(pthread_create(&tid1, NULL, filSuma, NULL)) {printf("\n ERROR creant fil 1"); exit(1);} if(pthread_create(&tid2, NULL, filSuma, NULL)) {printf("\n ERROR creant fil 2"); exit(1);} if(pthread_join(tid1, NULL)) /* espera finalitzacio del fil 1 */ {printf("\n ERROR join fil 1");exit(1);} if(pthread_join(tid2, NULL)) /* espera finalitzacio del fil 1 */ {printf("\n ERROR join fil 2"); exit(1);} if (comptador < 2 * NITER) printf("\nEI! el comptador es [%d], i hauria de ser %d\n", comptador, 2*NITER); else printf("\n D'acord! el comptador es [%d]\n", comptador); pthread_exit(NULL); }
Es pot compilar aquest codi amb:
$ gcc -o filsuma2 filsuma2.c -lpthread
Important utilitzar -lpthread per evitar els errors undefined reference:
filsuma2.c:(.text+0x29): undefined reference to `sem_init'
semaphore fillCount = 0 semaphore emptyCount = BUFFER_SIZE procedure producer() { while (true) { item = produceItem() down(emptyCount) putItemIntoBuffer(item) up(fillCount) } } procedure consumer() { while (true) { down(fillCount) item = removeItemFromBuffer() up(emptyCount) consumeItem(item) } }
Recursos:
Aquest mètode permet l'intercanvi de dades entre processos utilitzant un zona de memòria. La zona de memòria és independent de les zones de memòria de cada procés (per les raons de seguretat comentades anteriorment). Un procés crea la zona de memòria de forma que la reta de processos i puguin accedir.
És un mètode molt ràpid de comunicació (respecte a altres mètodes com les Pipes o els sockets). Una limitació clara és que els processos s'han d'executar a la mateixa màquina.
IPC per memòria compartida s'utilitza bàsicament en sistemes Unix o sistemes operatius que compleixen amb l'estàndard POSIX. POSIX proveïx d'una API anomenada POSIX Shared Memory:
Crida de sistema:
# include sys/mman.h shm_open()
Recursos:
int main(int argc, char argv[]) { int idProc; ... idProc =fork(); /* Després de la crida hauran 2 processo que son el mateix programa amb l’estat de la crida*/ if (idProc == -1) { /* El valor de retorn -1 és un error */ perror("Error al crear procés fill"); } else if (idProc == 0) { /* El 0 indica que es tracta del procés fill */ /* codi fill */ } else if (idProc != 0) { /* qualsevol altre valor indica que es el procés pare */ /* codi pare */ ... }
El següent programa:
#define entradaStandard 0 #define sortidaStandard 1 #define entradaTaulaTub 0 #define sortidaTaulaTub 1 int main( int argc, char* argv[] ) { int tub[2]; /* taula de descriptors del tub o pipe */ int idProces; /* identificaci� del proc�s fill */ char *fargv[3]; /* arguments de les comandes a executar*/ if (argc != 3) {printf( "Us: %s filter1 filter2\n", argv[0] ); exit(-1);} pipe( tub ); idProces = fork(); if ( idProces == 0 ) { close(sortidaStandard); dup ( tub[sortidaTaulaTub] ); close(tub[entradaTaulaTub]); close(tub[sortidaTaulaTub] ); fargv[0] = argv[1]; fargv[1] = 0; execve( argv[1], fargv, 0 ); perror( "filtre 1 ha fallat" ); } else { close(entradaStandard); dup ( tub[entradaTaulaTub] ); close( tub[entradaTaulaTub] ); close( tub[sortidaTaulaTub] ); fargv[0] = argv[2]; fargv[1] = 0; execve( argv[2], fargv, 0 ); perror( "filtre 2 ha fallat" ); } }
Aquest programa emula una pipe (|). Per exemple si executeu:
$ ./tub /bin/ls /usr/bin/wc
Tindrà el mateix efecte que:
$ ls | wc
O per exemple:
$ ./tub /bin/ls /bin/more
serà idèntic a:
$ ls | more
#define entradaStandard 0 #define sortidaStandard 1 #define entradaTaulaTub 0 #define sortidaTaulaTub 1 int main( int argc, char* argv[] ) { int tub[2]; /* taula de descriptors del tub o pipe */ int idProces; /* identificació del procés fill */ char *fargv[3]; /* arguments de les comandes a executar*/ /* Pas 0: assegurem que la comanda s'ha escrit correctament: Us: tub filtre1 filtre2 */ if (argc != 3) { printf( "Us: %s filter1 filter2\n", argv[0] ); exit(-1); } /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |-> teclat |->pantalla|->pantalla| | | +----------+----------+----------+----------+----------+ stdin stdout stderr +----+ teclat-->| |-->pantalla |pare|-->pantalla | | +----+ */ /* Pas 1: crea un pipe */ pipe( tub ); /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |-> teclat |->pantalla|->pantalla|->ent. tub|->sor. tub| +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ teclat-->| |-->pantalla |pare|-->pantalla +->| |--+ | +----+ | tub[0]=3| +----+ |tub[1]=4 +--|tub |<-+ +----+ */ /* Pas 2: bifurca un procés fill */ idProces = fork(); if ( idProces == 0 ) { /* es tracta del procés fill */ /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |-> teclat |->pantalla|->pantalla|->ent. tub|->sor. tub| +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ +----+ teclat-->| |-->pantalla teclat-->| |-->pantalla |pare|-->pantalla |fill|-->pantalla +->| |--+ +->| |--+ | +----+ | | +----+ | | +-------------+ | | +-------------+ +--------+-----+ | tub[0]=3| |+----+ |tub[1]=4 | +-+|tub |<-+----------------+ +----+ */ /* Pas 2a: tanquem la sortida standard original, dupliquem a la taula d'E/S del procés el descriptor de sortida del tub com sortida standard. Tancant els descriptors del tub, desapareixeran de la taula d'E/S en les posicions 3 i 4. */ close(sortidaStandard); /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |-> teclat | --- |->pantalla|->ent. tub|->sor. tub| +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ +----+ teclat-->| | teclat-->| | |pare|-->pantalla |fill|-->pantalla +->| |--+ +->| |--+ | +----+ | | +----+ | | +-------------+ | | +-------------+ +--------+-----+ | tub[0]=3| |+----+ |tub[1]=4 | +-+|tub |<-+----------------+ +----+ */ dup ( tub[sortidaTaulaTub] ); /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |-> teclat |->sor. tub|->pantalla|->ent. tub|->sor. tub| +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ +----+ teclat-->| | teclat-->| |->pantalla(stderr) |pare|-->pantalla |fill|--+(stdout) +->| |--+ +->| |--+ | +----+ | | +----+ | | +-------------+ | | +-------------+ +--------+-----+ | tub[0]=3| |+----+ |tub[1]=4 | +-+|tub |<-+----------------+ +----+ */ close(tub[entradaTaulaTub]); close(tub[sortidaTaulaTub] ); /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |-> teclat |->sor. tub|->pantalla| --- | --- | +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ +----+ teclat-->| | teclat-->| |->pantalla(stderr) |pare|-->pantalla |fill|--+(stdout) +->| |--+ | | | | +----+ | +----+ | | +-------------+ | +-------------+ | | tub[0]=3| +----+ |tub[1]=4 | +-+|tub |<-+----------------+ +----+ */
/* Pas 2b: ara solapem amb filtre 1 */ fargv[0] = argv[1]; fargv[1] = 0; execve( argv[1], fargv, 0 ); perror( "filtre 1 ha fallat" ); } else { /* procés pare */ /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |-> teclat |->sor. tub|->pantalla|->ent. tub|->sor. tub| +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ +----+ teclat-->| | teclat-->| |->pantalla(stderr) |pare|-->pantalla |fill|--+(stdout) +->| |--+ | | | | +----+ | +----+ | | +-------------+ | +-------------+ | | tub[0]=3| +----+ |tub[1]=4 | +-+|tub |<-+----------------+ +----+ */ /* Pas 2c: tanquem l'entrada standard original, dupliquem a la taula d'E/S del procés el descriptor d'entrada del tub com entrada standard. Tancant els descriptors del tub, desapareixeran de la taula d'E/S en les posicions 3 i 4. */ close(entradaStandard); /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ | --- |->sor. tub|->pantalla|->ent. tub|->sor. tub| +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ +----+ teclat-->| | teclat-->| |->pantalla(stderr) |pare|-->pantalla |fill|--+(stdout) +->| |--+ | | | | +----+ | +----+ | | +-------------+ | +-------------+ | | tub[0]=3| +----+ |tub[1]=4 | +-+|tub |<-+----------------+ +----+ */ dup ( tub[entradaTaulaTub] ); /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |->ent. tub|->sor. tub|->pantalla|->ent. tub|->sor. tub| +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ +----+ (stdin)+->| | teclat-->| |->pantalla(stderr) | |pare|-->pantalla (stdin) |fill|--+(stdout) +->| |--+ | | | | +----+ | +----+ | | +-------------+ | +-------------+ | | tub[0]=3| +----+ |tub[1]=4 | +-+|tub |<-+----------------+ +----+ */ close( tub[entradaTaulaTub] ); close( tub[sortidaTaulaTub] ); /* taula E/S 0 1 2 3 4 +----------+----------+----------+----------+----------+ |->ent. tub|->sor. tub|->pantalla| --- | --- | +----------+----------+----------+----------+----------+ stdin stdout stderr tub[0]=3 tub[1]=4 +----+ +----+ (stdin)+->| | teclat-->| |->pantalla(stderr) | |pare|-->pantalla (stdin) |fill|--+(stdout) | | | | | | | +----+ +----+ | | +----+ | +----------------|tub |<-+----------------+ +----+ */ /* Pas 2d: ara solapem amb filtre 2 */ fargv[0] = argv[2]; fargv[1] = 0; execve( argv[2], fargv, 0 ); perror( "filtre 2 ha fallat" ); } }
#include <pthread.h> #include <semaphore.h> #include <stdio.h> #include <stdlib.h> #define NITER 1000000 int comptador = 0; sem_t mutex; void * filSuma(void * a) { int i, tmp; for(i = 0; i < NITER; i++) { tmp = comptador; /* copia el comptador global a un de local */ tmp = tmp+1; /* incrementa la copia local */ comptador = tmp; /* guarda el valor local al comptador global*/ } } int main(int argc, char * argv[]) { pthread_t tid1, tid2; sem_init(&mutex, 0, 1); if(pthread_create(&tid1, NULL, filSuma, NULL)) {printf("\n ERROR creant fil 1"); exit(1);} if(pthread_create(&tid2, NULL, filSuma, NULL)) {printf("\n ERROR creant fil 2"); exit(1);} if(pthread_join(tid1, NULL)) /* espera finalitzacio del fil 1 */ {printf("\n ERROR join fil 1");exit(1);} if(pthread_join(tid2, NULL)) /* espera finalitzacio del fil 1 */ {printf("\n ERROR join fil 2"); exit(1);} if (comptador < 2 * NITER) printf("\nEI! el comptador es [%d], i hauria de ser %d\n", comptador, 2*NITER); else printf("\n D'acord! el comptador es [%d]\n", comptador); pthread_exit(NULL); }
Consulteu Execució_de_comandes_i_aplicacions_en_C.
Consulteu Implementació de comandes de shell amb crides de sistema.
En el cas que no trobem alguna crida al sistema en el manual haurem d'instal·lar els següents paquets:
$ sudo apt-get install manpages-dev
També pot ser útil disposar dels manuals en castellà:
$ sudo apt-get install manpages-es
Atenció: No tots els manuals estan tradüits. A més si esteu treballant en català i voleu veure els manuals en castellà, heu d'afegir el següent al fitxer .bashrc de la vostre HOME:
alias man='man -L es'
O simplement recordar-vos de posar els paràmetres -L es després de la comanda man.
En tot cas si encara i així no trobem alguna crida al sistema o comanda a man podem seguir el següent procés per mirar de veure quin paquet ens falta. Primer anem a la carpeta on es troben els manuals:
$ cd /usr/share/man
Si us fixeu en aquesta carpeta hi ha una carpeta per cada secció de man (man1, man2, man3 ,etc). Com ja hem comentat les crides a sistema es troben al nivell 2:
$ cd man2
Imagineu que volem veure si tenim el manual de open. Executaríem:
$ ls -la | grep open lrwxrwxrwx 1 root root 9 2005-07-20 20:47 creat.2.gz -> open.2.gz -rw-r--r-- 1 root root 5588 2004-11-02 10:43 open.2.gz
Vom podeu veure el fitxer open.gz ens proporciona el manual. Per tant per saber quin paquet ens proporciona aquest fitxerr podem executar:
$ dpkg -S open.2.gz manpages-es: /usr/share/man/es/man2/open.2.gz manpages-dev: /usr/share/man/man2/open.2.gz
Com podeu veure els paquet que proporciona aquest fitxer és manpages-dev.
Recursos: