SWI015 Příklady
Z ωικι.matfyz.cz
Obsah
Příklady k předmětu Unix
Simulace činnosti shellu
Zadání
Napište program, který simuluje činnost shellu při interpretaci skriptu
for F in "$@"; do /usr/bin/grep '^#' "$F"; done 2>/dev/null | less
Řešení
- Především je potřeba si uvědomit, co všechno dělá shell, to samé by měl dělat i program.
- Dále je potřeba pochytat všechny konce roury, včetně těch, co duplikuje fork(), jinak roura prostě nechodí dobře.
- Nezapomeňte ukončit seznam parametrů funkcí execl() a execlp() hodnotou NULL, abyste se vyhnuli odpoledni zoufalého ladění, které zastihlo mě při psaní zápočťáku.
- (Pokud nevznikla chyba při editaci na wiki, tak by to mělo chodit.)
#include <unistd.h> /* fork(), pipe(), dup2(), close(), exec*, ...*/ #include <sys/wait.h> /* wait() */ #include <sys/types.h> /* pid_t */ #include <stdlib.h> /* exit() */ #include <fcntl.h> /* O_WRONLY, ... */ void test_rval(int rval, char* msg); /*** main ***/ int main(int argc, char *argv[]) { int pipe_fd[2]; /* pipe descriptors */ pid_t pid; /* child PID */ int status; /* wait status */ int null_fd; /* fd of /dev/null */ int i, rval; rval = pipe(pipe_fd); /* init pipe */ test_rval(rval, "pipe()"); pid = fork(); /* split to: for | less */ test_rval(pid, "fork(1)"); /* leaving out the rest of the tests to be brief */ if( pid == 0 ) { /* child */ close(pipe_fd[0]); /* duplicated by fork */ for(i = 1; i < argc; i++) /* call grep for each parameter */ { pid = fork(); /* fork again to call grep */ if( pid == 0 ) { /* grand-child */ /* redirect stderr to /dev/null - we could do it for our parent at once, * but it would require another pipe to feed the parent */ null_fd = open("/dev/null", O_WRONLY); dup2(null_fd, 2); close(null_fd); dup2(pipe_fd[1], 1); /* redirect output to the pipe */ close(pipe_fd[1]); /* call grep - remember that "'^#'" would search for '^#' including quotes */ execl("/usr/bin/grep", "grep", "^#", argv[i], NULL); test_rval(-1, "exec(grep)"); } else { /* parent (and also child of grand parent)*/ wait(&status); /*wait for grep to finish*/ } } /* /for */ close(pipe_fd[1]); } else { /* parent - execute less */ close(pipe_fd[1]); /* duplicated by fork */ dup2(pipe_fd[0], 0); /* stdin from pipe */ close(pipe_fd[0]); execlp("less", "less", NULL); /* run less */ test_rval(-1, "execlp(less)"); /* should not be reached on success call */ } return EXIT_SUCCESS; } /* /main */ void test_rval(int rval, char* msg) { if( rval == -1 ) { perror(msg); exit(EXIT_FAILURE); } } /* end */
Udržování konstantního počtu threadů
Zadání
Napište aplikaci, která bude stále udržovat konstantní počet threadů. Thread vznikne a uspí se na náhodnou dobu. Potom zase umře. Důraz se klade na synchronizační primitiva.
Řešení
#include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <fcntl.h> #include <sys/types.h> #include <string.h> #include <unistd.h> #include <pthread.h> static struct option longopts[] = { { "count", required_argument, NULL, 'c' }, { NULL, 0, NULL, 0 } }; #define MAX 10 pthread_mutex_t mutex_stop = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_stop = PTHREAD_COND_INITIALIZER; int thread_stop_number = -1; int random_number = 0; int rnd() { int cislo = rand(); while (cislo > MAX) cislo = cislo % MAX; return cislo; } void * thread(void * x) { int time = rnd(); int thr_id = (int) x; int work=1; printf("thread %d started\n", thr_id); sleep(time); // inform main while(work){ pthread_mutex_lock(&mutex_stop); if(thr_id!=-1){ pthread_mutex_unlock(&mutex_stop); continue; } work=0; } thread_stop_number = thr_id; pthread_cond_signal(&cond_stop); pthread_mutex_unlock(&mutex_stop); printf("thread %d: after %d second(s) ended\n", thr_id, time); return NULL; } void start(int i) { pthread_t newthr; pthread_create(&newthr, NULL, thread, (void *) i); pthread_detach(newthr); return; } void * runner() { pthread_mutex_lock(&mutex_stop); while(1) { pthread_mutex_lock(&mutex_stop); while(thread_stop_number == -1) pthread_cond_wait(&cond_stop,&mutex_stop); // start new thread start(thread_stop_number); // set data thread_stop_number = -1; pthread_mutex_unlock(&mutex_stop); } pthread_mutex_unlock(&mutex_stop); return NULL; } void * starter(void * arg) { // start all threads at the beginning int count = (int) arg; int i; for(i = 0; i < count; i++) start(i); return NULL; } int main(int argc, char **argv) { // read options int count = 10; char ch; while ((ch = getopt_long(argc, argv, "c:", longopts, NULL)) != -1) switch(ch) { case 'c': count = atoi(optarg); break; case 'd': break; default: puts("test\n"); return(1); } argc -= optind; argv += optind; pthread_t thr; pthread_t sthr; pthread_create(&thr, NULL, runner, NULL); pthread_create(&sthr, NULL, starter, (void *) count); pthread_join(thr, NULL); return 0; }
Makefile:
EXECUTABLE = thread SOURCES = moje.c OBJECTS = $(SOURCES:.c=.o) CC = gcc CFLAGS = -c -Wall -o LDFLAGS = -lpthread -o all: $(EXECUTABLE) clean: rm *.o $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CC) $(LDFLAGS) $@ $^ $(OBJECTS): $(SOURCES)
Bariéra pro vlákna
Zadání
Napište barieru pro vlákna. V aplikaci vznikne několik vláken, ta se uspí na náhodnou dobu, a po probuzení dojedou k bariéře, kde na sebe počkají. Využijte podmínkové proměnné, aktivní čekání není přípustné.
Řešení
#include <pthread.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #define NTHREADS 5 typedef struct { pthread_mutex_t *lock; pthread_cond_t *cv; int *ndone; int id; } TStruct; void* barrier(void *arg) { TStruct *ts; int i; ts = (TStruct *) arg; // do something usefull here { sleep((int)(( ((float) random())/RAND_MAX)*10 )); } printf("Thread %d -- waiting for barrier\n", ts->id); pthread_mutex_lock(ts->lock); printf("mutex %d locked by thread id: %d\n",(int) ts->lock , ts->id); *ts->ndone = *ts->ndone + 1; while (*ts->ndone < NTHREADS) { //printf("thread %d is waiting...: \n", ts->id); pthread_cond_wait(ts->cv, ts->lock); } // { for (i = 1; i < NTHREADS; i++) pthread_cond_signal(ts->cv); } printf("mutex unlocked by thread id: %d\n", ts->id); pthread_mutex_unlock(ts->lock); printf("Thread %d -- after barrier\n", ts->id); return NULL; } int main() { TStruct ts[NTHREADS]; pthread_t tids[NTHREADS]; int i, ndone; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cv; void *retval; pthread_mutex_init(&lock, NULL); pthread_cond_init(&cv, NULL); ndone = 0; for (i = 0; i < NTHREADS; i++) { ts[i].lock = &lock; ts[i].cv = &cv; ts[i].ndone = &ndone; ts[i].id = i; } for (i = 0; i < NTHREADS; i++) { pthread_create(tids+i, NULL, barrier, ts+i); } for (i = 0; i < NTHREADS; i++) { pthread_join(tids[i], &retval); } pthread_mutex_destroy(&lock); pthread_cond_destroy(&cv); printf("done\n"); return 0; }