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 "
ParseError: KaTeX parse error: Expected group after '^' at position 23: …/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)
$(CC) $(LDFLAGS) $@ $^
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 = ts\[i].cv = ts\[i].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;
}