Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ. (επεξεργασμένο)

Στο μάθημα Ταυτόχρονου προγραμματισμού της σχολής βλέπω ο καθηγητής ζητάει να υλοποιήσουμε συναρτήσεις up(binary semaphore) και down(binary semaphore) χρησιμοποιώντας της συναρτήσεις της pthread mutex_init,  mutex_lock και mutex_unlock. Κοιτάζοντας το man της lock βλέπω: "If a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked, undefined behavior results." που αν έχω καταλάβει καλά, είναι κάτι που πρέπει να κάνει ένας σηματοφόρος.

Φτιάχνω τις συναρτήσεις (δε βάζω κώδικα γιατί είναι μέρος άσκησης).  Χονδρικά ένα struct με 2 mutex και ένα int. Στο int κρατάω τη τιμή του σηματοφόρου (0 ή 1), ένα mutex για τη προστασία της τιμής και ένα ακόμα για να κάνω μπλοκάρω το thread. Tις χρησιμοποιώ για να υλοποιήσω ένα sleeping barber αλγόριθμο που έχει στις διαλέξεις. Φαίνεται να δουλεύει και μου κάνει εντύπωση. Τυχαίνει ή δεν εμπίπτει στο undefined behaviour του quote?

Spoiler

#include "../bsem.h"
#include <unistd.h>

#define N 20

int array[N];
int customer_array_pointer = 0;

int avl = 0;
sem mtx, sleep_sem;

void *barber();
void *customer(void *t);

int main (int argc, char *argv[]){

    init(&mtx, 1);
	init(&sleep_sem,0);
   

    pthread_t barber_thread;
    if(pthread_create(&barber_thread, NULL, barber, NULL)){
        printf("error thread1\n");
        return EXIT_FAILURE;
    }
	
	pthread_t *customer_thread = malloc(sizeof(pthread_t)*N);  //Max N customers
	int time;
	printf("Enter customer time\n");
	scanf("%d", &time);
	int i =0;
	while(time!=0 && i<N){
		if(pthread_create(&customer_thread[i], NULL, customer, (void *)&time)){
			printf("error thread1\n");
			return EXIT_FAILURE;
		}
		i++;
		printf("Enter customer time\n");
		scanf("%d", &time);
	}

    pthread_join(barber_thread, NULL);

    return EXIT_SUCCESS;
}

void *customer(void *t){
        
	down(&mtx);
	
	array[customer_array_pointer]= *(int *)t;
	customer_array_pointer++;
	avl++;
	if (avl == 0) {
		up(&sleep_sem);
	}

	up(&mtx);

	return NULL;
}

void *barber(){

	int j=0;

	while(1){
		
		down(&mtx);

		avl--;
        if(avl == -1){printf("sleeping\n");
			up(&mtx);
			down(&sleep_sem);
			up(&mtx);
		}

        up(&mtx);

		for (int i=0;i<array[j];i++){
			printf("working for client: %d with time: %d. Time remaining: %d\n", j, array[j], array[j]-i);
			sleep(1);
		}
		j++;

	}

	return NULL;
}

 

Αυτό που καταλαβαίνω είναι ότι το thread του barber κλειδώνει το mutex του sleep_sem (όταν δεν υπάρχει πελάτης διαθέσιμος) και το ξεκλειδώνει το πρώτο thread customer.

Επεξ/σία από sir ImPeCaBlE
Δημοσ.

Ub ειναι επειδη δεν υπαρχει περίπτωση να κανεις unlock και να εχεις γραψει σωστο κωδικα. Γιατι να κανεις unlock ενα mutex που δεν εχει γινει lock; 

Δημοσ.

"If a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked, undefined behavior results."

Για το bold ήταν η απορία μου. Δηλαδή στο παράδειγμα του sleeping barber, το mutex του sleep_sem κλειδώθηκε από το thread του barber αλλά ξεκλειδώθηκε από ένα thread customer. Και φαίνεται να δουλεύει χωρίς θέμα. Και σε άλλα προγραμματάκια που δοκίμασα, λειτούργησε όπως περίμενα.

Τέσπα, από ότι καταλαβαίνω είναι ub αλλά ταυτόχρονα "δουλεύει" γιατί βλέπω λύσεις στο github από συμφοιτητές μου και όλοι παρόμοια λύση έχουμε. Ίσως έχει ειπωθεί κάτι στα φροντιστήρια του μαθήματος, που δεν τα παρακολούθησα.

Δημοσ.

Αν ειναι να κλειδωνεις ενα mutex στο α νημα, και να το ξεκλειδωνεις στο β νημα, τοτε το "φαινεται να δουλευει" μεταφραζεται σε δεν δουλευει. 

 

Δημοσ.

Δεν καταλαβαίνω πολλά πράγματα εδώ, αλλά το βασικότερο είναι το εξής.

Λες ότι το manual αναφέρει XYZ για μια function, την οποία δε βλέπω να καλεί πουθενά ο κώδικας που δίνεις (έκανα find το όνομα της). Άρα τι σχέση έχει το ένα με το άλλο;

Δημοσ.

Οι mutex_lock και mutex_unlock χρησιμοποιούνται στις συναρτήσεις μου down(*sem) και up(*sem). Το sem είναι το struct που περιγράφω στο πρώτο ποστ. Δεν έβαλα το κώδικα για τις συναρτήσεις γιατί είναι άσκηση του μαθήματος. Αφού όμως τελικά υπάρχουν ήδη λύσεις στο github αν είναι να βοηθήσει, τις κάνω ένα cp. Δε νομίζω ότι έχει ιδιαίτερο νόημα όμως.

Χονδρικά όταν καλείται η down(*sem) ουσιαστικά γίνεται mutex_lock για το mutex_t του struct sem. Και όταν καλείται η up(*sem), αν έχει προηγηθεί κλήση της mutex_lock τότε εκτελείται mutex_unlock για το mutex_t του struct sem.

Δημοσ.
Στις ‎31‎/‎8‎/‎2018 στις 11:10 ΜΜ, sir ImPeCaBlE είπε

 

Αυτό που καταλαβαίνω είναι ότι το thread του barber κλειδώνει το mutex του sleep_sem (όταν δεν υπάρχει πελάτης διαθέσιμος) και το ξεκλειδώνει το πρώτο thread customer.

Σωστά καταλαβαίνεις εκτός από το εξής: Η sleep_sem δεν είναι mutex. Mutex είναι η mtx.

Διάβασε εδώ: https://www.geeksforgeeks.org/mutex-vs-semaphore/

και εδώ: (από Λειτουργικά Συστήματα του Tanenbaum): http://web.cecs.pdx.edu/~harry/Blitz/OSProject/p3/SleepingBarberProblem.pdf

Δημοσ. (επεξεργασμένο)

Και οι 2 struct sem είναι, οπότε ουσιαστικά mutex :P. Τουλάχιστον στην υλοποίησή μου. Η mtx θα μπορούσε να είναι ένα απλό mutex αλλά έτσι και αλλιώς δε δημιουργεί πρόβλημα.

Επεξ/σία από sir ImPeCaBlE
Δημοσ. (επεξεργασμένο)

Δεν ξέρω, πολύ μπέρδεμα, μισές πληροφορίες και γενικά δύσκολο να βγει άκρη τι κάνεις εκεί.

Δεν καταλαβαίνω ούτε με ποια λογική μπορεί να θες να κάνεις αυτό που γράφεις στο αρχικό ποστ, ότι ένα θρεντ κλειδώνει και ένα άλλο ξεκλειδώνει. By definition murex κλειδώνεις, κάνεις μια δουλειά και αμέσως ξεκλειδώνεις. Πάντα στο ίδιο θρεντ. Πας να χρησιμοποιήσεις το mutex σαν κάποιου είδους event? 

Επεξ/σία από defacer
Δημοσ. (επεξεργασμένο)

Εγώ θέλω να φτιάξω δυαδικούς σηματοφόρους χρησιμοποιώντας mutex.

My bad. Μπερδευτήκαμε πολύ. Βάζω την εκφώνηση: "Υλοποιήστε, ως ξεχωριστό τμήμα λογισμικού στο πνεύμα μιας βιβλιοθήκης, τους δικούς σας δυαδικούς σηματοφόρους, χρησιμοποιώντας mutexes και τις λειτουργίες mutex_init, mutex_lock και mutex_unlock της βιβλιοθήκης pthreads. Επιχειρηματολογήστε για το αν η υλοποίηση σας εγγυάται δικαιοσύνη."

H βιβλιοθήκη μου έχει 3 συναρτήσεις: init(*sem), up(*sem), down(*sem). Το sem είναι το struct που ανέφερα δηλαδή 1 int και 2 pthread_mutex_t. Τον ένα mutex το χρησιμοποιώ όταν πειράζω/ελέγχω το int του struct. Το άλλο το χρησιμοποιώ για να μπλοκάρω και να ξεμπλοκάρω το νήμα (προφανώς από άλλο νήμα άρα καταλήγω σε ub). Δε μπορώ να σκεφτώ άλλη υλοποίηση με βάση την εκφώνηση.

Επεξ/σία από sir ImPeCaBlE
Δημοσ. (επεξεργασμένο)

Γενικά μιλώντας, με "κλασικό" mutex αυτό που θες δεν γίνεται (εδώ έχεις UB), ή τέλος πάντων γίνεται μόνο με απαράδεκτο τρόπο (busy wait).

At this stage έχω αρχίσει να σκέφτομαι πως απλά αυτός που έβαλε την άσκηση αγνοεί τελείως το UB της υπόθεσης προκειμένου να σας βάλει να σκεφτείτε πώς θα κάνετε κάτι αγνοώντας ότι ποτέ κανένας δε θα έπρεπε να κάνει αυτό το κάτι με αυτόν τον τρόπο. Το οποίο κατά την άποψη μου είναι ντιπ ηλίθιο.

Επεξ/σία από defacer
Δημοσ. (επεξεργασμένο)
Στις 4/9/2018 στις 9:13 ΠΜ, sir ImPeCaBlE είπε

"If a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked, undefined behavior results."

Για το bold ήταν η απορία μου.

 

Edit: Έσβησα το χαλασμένο μήνυμα. Ολόκληρη η απάντηση παρακάτω.

Επεξ/σία από imitheos
Δημοσ.

Ασκήσεις με ενεργή αναμονή είχε στο προηγούμενο set ασκήσεων, οπότε δε νομίζω ότι θέλει κάτι τέτοιο τώρα. Τέσπα, αυτό το μάθημα είναι τελείως εισαγωγικό, οπότε μάλλον κάτι σαν αυτό που λες θα ισχύει. Επίσης όπως είπα:

Στις 4/9/2018 στις 9:13 ΠΜ, sir ImPeCaBlE είπε

Ίσως έχει ειπωθεί κάτι στα φροντιστήρια του μαθήματος, που δεν τα παρακολούθησα.

 

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...