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: date | nc -u :: 6666
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
");}
}