Ahoj,
v rámci přípravy jsem si vypracoval pár příkladů podobných minulým zkouškám. Upozorňuji, že jsem UNIXové API nikdy moc nepoužíval, takže tam budou různé věci blbě.
Budete potřebovat nsautil.h a jcc z blobutils
Zdroje: http://mff.devnull.cz/pvu/common/zkousk ... ousek.html a toto fórum.
Příklad: Nasimulujte shellovou kolonu cat /proc/cpuinfo | grep model | tr a-z A-Z | sed -r "s/(A|E|I|O|U)/_/g"
#include <nsautil.h> int main(int argc, char **argv) { pid_t child;int filedes[2];int pipeprev = -1; pipe(filedes);child = fork();if(child == 0) {dup2(filedes[1], STDOUT_FILENO);close(filedes[1]);execlp("cat", "cat", "/proc/cpuinfo", NULL);}close(filedes[1]);close(STDIN_FILENO);pipeprev = filedes[0]; pipe(filedes);child = fork();if(child == 0) {dup2(pipeprev, STDIN_FILENO);dup2(filedes[1], STDOUT_FILENO);close(filedes[1]);execlp("grep", "grep", "model", NULL);}close(filedes[1]);close(pipeprev);pipeprev = filedes[0]; pipe(filedes);child = fork();if(child == 0) {dup2(pipeprev, STDIN_FILENO);dup2(filedes[1], STDOUT_FILENO);close(filedes[1]);execlp("tr", "tr", "a-z", "A-Z", NULL);}close(filedes[1]);close(pipeprev); child = fork();if(child == 0) {dup2(filedes[0], STDIN_FILENO);//close(filedes[0]);execlp("sed", "sed", "-r", "s/(A|E|I|O|U)/_/g", NULL);}close(filedes[0]); return 0; }
(jako cvičení by bylo vhodné parametrizovat to příkazy v poli + execvp)
Příklad: Hlavní vlákno vytvoří počet vláken zadaný jako parametr příkazové řádky. Každé vlákno simuluje činnost pomocí sleep() na náhodnou dobu, 1 až 10 sekund. Po vykonání činnosti, tj. po ukočení funkce sleep(), vlákno zahlásí hlavnímu vláknu, že skončilo. Hlavní vlákno okamžitě vytvoří další vlákno.
Cílem je tedy udržovat stále stejný počet vláken v běhu. Každé vlákno má navíc svoje pořadové číslo, při vytvoření a zániku vlákna se vypíše na termínál hlášení o této skutečnosti, s použitím pořadového čísla.
Pro synchronizaci použijte mutexy a podmínkové proměnné. Aktivní čekání je nepřípustné. Velký důraz je kladen na korektnost použití synchronizačních primitiv.
Usage: ./pthreads 10
#include <nsautil.h> #include <pthread.h> #include <poll.h> pthread_mutex_t mujmutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t mojecond = PTHREAD_COND_INITIALIZER; int numt; int * r; typedef struct tr {int tid;int toffs;char * message;pthread_t thr; } tr; tr * t; void * mujthread(void *ptr) {tr * ctx = (tr*)ptr;printf("Thread %i(%i) is running ", ctx->toffs, ctx->tid); poll(NULL, 0, random() % 10000); // for(volatile int i = 0; i<100*1000*1000; i++) {} printf("Thread %i(%i) says: %s ", ctx->toffs, ctx->tid, ctx->message); poll(NULL, 0, random() % 10000); printf("Thread %i(%i) is finishing ", ctx->toffs, ctx->tid); r[ctx->tid] = 0; pthread_cond_signal(&mojecond); return(NULL); } int main(int argc, char ** argv) { numt = atoi(argv[1]); r = malloc(sizeof(int) * numt);t = malloc(sizeof(tr) * numt); int iter = 0;int toffs = 0;while (1) {pthread_mutex_lock(&mujmutex);iter++;for (int i = 0; i<numt; i++) {if (r[i] == 0) {pthread_join(t[i].thr, NULL);pthread_t thr;t[i].message = (char*)malloc(100);sprintf(t[i].message, "This is iter %i", iter);t[i].tid = i;t[i].toffs = toffs;int ret = pthread_create(&thr, NULL, &mujthread, (void*) (t + i));t[i].thr = thr;toffs++;if(ret == 0) {r[i] = 1;} else {printf("Cannot create thread! ");}}}pthread_cond_wait(&mojecond, &mujmutex);pthread_mutex_unlock(&mujmutex);} exit(EXIT_SUCCESS); }
Příklad: datagram server, IP agnostic. Kvůli bugu v glibc (https://sourceware.org/bugzilla/show_bug.cgi?id=9981) to není úplně agnostic, je tam ten if(rp->ai_family == AF_INET).
Usage:
Vrátí datum s čísly přepsanými křížky.
#include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #define BUF_SIZE 500 /* Zkopírováno z manpage getaddrinfo z glibc a z https://stackoverflow.com/questions/5956516/getaddrinfo-and-ipv6 */ int main(int argc, char *argv[]) { struct addrinfo hints;struct addrinfo *result, *rp;int sfd, s;struct sockaddr_storage peer_addr;socklen_t peer_addr_len;ssize_t nread;char buf[BUF_SIZE]; if (argc != 2) {fprintf(stderr, "Usage: %s port ", argv[0]);exit(EXIT_FAILURE);} memset(&hints, 0, sizeof(struct addrinfo));hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */hints.ai_socktype = SOCK_DGRAM;hints.ai_flags = AI_PASSIVE;hints.ai_protocol = 0; /* Any protocol */hints.ai_canonname = NULL;hints.ai_addr = NULL;hints.ai_next = NULL; s = getaddrinfo(NULL, argv[1], &hints, &result);//s = getaddrinfo("localhost", argv[1], &hints, &result);if (s != 0) {fprintf(stderr, "getaddrinfo: %s ", gai_strerror(s));exit(EXIT_FAILURE);} /* getaddrinfo() returns a list of address structures. Try each address until we successfully bind(2). If socket(2) (or bind(2)) fails, we (close the socket and) try the next address. */ for (rp = result; rp != NULL; rp = rp->ai_next) { if(rp->ai_family == AF_INET6) {char * buf = malloc(INET6_ADDRSTRLEN);struct sockaddr_in* saddr = (struct sockaddr_in*)rp->ai_addr;if(inet_ntop(AF_INET6, &(saddr->sin_addr), buf, INET6_ADDRSTRLEN)) {printf("Trying (v6) %s ", buf);} else {printf("ntop err ");}} else if (rp->ai_family == AF_INET) {char * buf = malloc(INET_ADDRSTRLEN);struct sockaddr_in* saddr = (struct sockaddr_in*)rp->ai_addr;if(inet_ntop(AF_INET, &(saddr->sin_addr), buf, INET_ADDRSTRLEN)) {printf("Trying (v4) %s ", buf);} else {printf("ntop err ");}} if(rp->ai_family == AF_INET) {continue;} sfd = socket(rp->ai_family, rp->ai_socktype,rp->ai_protocol);if (sfd == -1) {continue;} if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) {printf(" ...bound OK ");break;} close(sfd);} if (rp == NULL) { /* No address succeeded */fprintf(stderr, "Could not bind ");exit(EXIT_FAILURE);} freeaddrinfo(result); /* No longer needed */ /* Read datagrams and echo them back to sender */ for (;;) {peer_addr_len = sizeof(struct sockaddr_storage);nread = recvfrom(sfd, buf, BUF_SIZE, 0,(struct sockaddr *) &peer_addr, &peer_addr_len);if (nread == -1)continue; /* Ignore failed request */ char host[NI_MAXHOST], service[NI_MAXSERV]; s = getnameinfo((struct sockaddr *) &peer_addr,peer_addr_len, host, NI_MAXHOST,service, NI_MAXSERV, NI_NUMERICSERV);if (s == 0)printf("Received %ld bytes from %s:%s ",(long) nread, host, service);elsefprintf(stderr, "getnameinfo: %s ", gai_strerror(s)); for(int i = 0; i<nread; i++) {if(buf[i] >= '0' &&buf[i] <= '9') {buf[i] = '#';}} if (sendto(sfd, buf, nread, 0,(struct sockaddr *) &peer_addr,peer_addr_len) != nread)fprintf(stderr, "Error sending response ");} }