SWI015 Příklady
Z ωικι.matfyz.cz
Obsah
Příklady k předmětu Unix[editovat | editovat zdroj]
Simulace činnosti shellu[editovat | editovat zdroj]
Zadání[editovat | editovat zdroj]
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í[editovat | editovat zdroj]
- 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ů[editovat | editovat zdroj]
Zadání[editovat | editovat zdroj]
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í[editovat | editovat zdroj]
#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[editovat | editovat zdroj]
Zadání[editovat | editovat zdroj]
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í[editovat | editovat zdroj]
#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;
}