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)
(OBJECTS)
$(CC) $(LDFLAGS) $@ $^
(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 = 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;
}