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)

(EXECUTABLE):(EXECUTABLE): (OBJECTS)

 $(CC) $(LDFLAGS) $@ $^

(OBJECTS):(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 = ￾
 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;

}