You are on page 1of 6

3η ΕΡΓΑΣΤΗΡΙΑΚΗ ΑΣΚΗΣΗ – ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ

ΚΟΥΤΡΑΣ ΧΡΗΣΤΟΣ 03114775 oslabd18

ΖΑΦΕΙΡΟΠΟΥΛΟΣ ΝΙΚΟΣ 03114431

1.1)
ΚΩΔΙΚΑΣ

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
void *increase_fn(void *arg)
{
int i;
volatile int *ip = arg;

fprintf(stderr, "About to increase variable %d times\n", N);


for (i = 0; i < N; i++) {
if (USE_ATOMIC_OPS) {
/* ... */
/* You can modify the following line */
__sync_add_and_fetch(ip,1);
/* ... */
} else {
/* ... */
pthread_mutex_lock(&mutex);
/* You cannot modify the following line */
++(*ip);
pthread_mutex_unlock(&mutex);
/* ... */
}
}
fprintf(stderr, "Done increasing variable.\n");

return NULL;
}

void *decrease_fn(void *arg)


{
int i;
volatile int *ip = arg;

fprintf(stderr, "About to decrease variable %d times\n", N);


for (i = 0; i < N; i++) {
if (USE_ATOMIC_OPS) {
/* ... */
/* You can modify the following line */
__sync_sub_and_fetch(ip,1);
/* ... */
} else {
/* ... */
pthread_mutex_lock(&mutex);
/* You cannot modify the following line */
--(*ip);
pthread_mutex_unlock(&mutex);
/* ... */
}
}
fprintf(stderr, "Done decreasing variable.\n");

return NULL;
}

Αποτελέσματα:

1)

Χωρις συγχρονισμο
real 0m0.039s
user 0m0.064s
sys 0m0.008s

με
atomic
real 0m0.412s
user 0m0.812s
sys 0m0.000s

mutex
real 0m3.866s
user 0m3.788s
sys 0m3.176s

Στην εκτέλεση χωρίς συγχρονισμό οι εντολές εκτελούνται με το βέλτιστο τρόπο από μεριάς
ταχύτητας αλλά προφανώς δεν έχουμε τα επιθυμιτά αποτελέσματα λόγω race conditions.
Αντίθετα οι άλλες δύο περιπτώσεις, atomic και mutex, είναι πιο αργές γιατί επιβάλλουν τη
σειρά με την οποία θα εκτελεστούν οι εντολές.
2) Πιο γρήγορη μέθοδος ειναι η χρήση atomic ops, γιατί όπως φαίνεται στα ερωτήματα 3
και 4, οι ατομικές λειτουργίες εκτελούνται σε μία γραμμή Assembly ενώ τα mutexes κάνουν
κλήση μια άλλη υπορουτίνα του λειτουργικού.

3)

.loc 1 49 0
movq -16(%rbp), %rax
lock addl $1, (%rax)

.loc 1 75 0
movq -16(%rbp), %rax
lock subl $1, (%rax)

4)

.loc 1 53 0
movl $mutex, %edi
call pthread_mutex_lock

1.2)

ΚΩΔΙΚΑΣ
/*GLOBAL*/
sem_t *s;
int *n;
/*...*/
void *computel(void *arg){
volatile int *thread=arg;
int i;
int color_val[x_chars];

for(i=*thread; i<y_chars; i+=*n){


compute_mandel_line(i, color_val);
sem_wait(&s[*thread]);
output_mandel_line(1, color_val);
if(*thread==(*n-1)) sem_post(&s[0]);
else sem_post(&s[*thread+1]);
}
return NULL;
}
/*...*/
/*main*/
int main(int argc,char *argv[])
{
int ret,i,thrcnt=0;
xstep = (xmax - xmin) / x_chars;
ystep = (ymax - ymin) / y_chars;

if(argc!=2){
printf("Correct usage of %s is with exactly one arguement\n",argv[0]);
exit(1);
}

if (safe_atoi(argv[1], &thrcnt) < 0 || thrcnt <= 0) {


fprintf(stderr, "`%s' is not valid for `thread_count'\n", argv[1]);
exit(1);
}
n=&thrcnt;
int arr[thrcnt];
pthread_t t[thrcnt];

s=malloc(thrcnt*sizeof(sem_t));
sem_init(&s[0], 0, 1);
for(i=0; i<thrcnt; i++){
if(i!=0) sem_init(&s[i], 0, 0);
arr[i]=i;
ret = pthread_create(&t[i], NULL, computel, &arr[i]);
printf("thread %d created\n",arr[i]);
if (ret) {
perror_pthread(ret, "pthread_create");
exit(1);
}
}

/*
* draw the Mandelbrot Set, one line at a time.
* Output is sent to file descriptor '1', i.e., standard output.
*/

for(i=0; i<thrcnt; i++){


ret = pthread_join(t[i], NULL);
if (ret)
perror_pthread(ret, "pthread_join");
}

reset_xterm_color(1);
free(s);
return 0;
}
Έξοδος εκτελέσιμου:

1)

Χρησιμοποιούμε τόσους σημαφόρους όσος και ο αριθμός των νημάτων.

2)

Χρόνος εκτέλεσης με 2 νήματα (παράλληλο)

real 0m0.518s
user 0m0.996s
sys 0m0.004s

Χρόνος εκτέλεσης αρχικού προγράμματος (σειριακό)

real 0m1.021s
user 0m0.984s
sys 0m0.012s

3) Το πρόγραμμα που υλοποιήσαμε εμφανίζει επιτάχυνση ανάλογη με τον αριθμό των


νημάτων που δέχεται ως είσοδο.

4) Θα μπορούσαμε να υλοποιήσουμε ενα signal handler για το σημα SIGINT ο οποίος θα


τρέχει ασύγχρονα από το υπόλοιπο πρόγραμμα και θα εκτελεί την εντολή
reset_xterm_color(1).

You might also like