Wątki : jaka jest różnica ?

Odpowiedz Nowy wątek
2005-12-07 01:39
0

Napisałem program obrazujący problem producent - konsument wykorzystujący wątki.

//deklaracje globalne
int bufor;
pthread_mutex_t producent_mutex=PTHREAD_MUTEX_INITIALIZER, konsument_mutex=PTHREAD_MUTEX_INITIALIZER;

//fragment main()
int main () {
...
    pthread_mutex_lock(&konsument_mutex);
    pthread_mutex_unlock(&producent_mutex);

    pthread_create(&producent_t, NULL, producent, &x);
    pthread_create(&konsument_t, NULL, konsument, &x);
...
}

void *producent (void *arg){
int x, i, produkt;
    for (i=0;i<=10;i++) {
        produkt=random()%100;
        pthread_mutex_lock(&producent_mutex);
        bufor=produkt; //<-zakomentowac
        printf("Producent : Wkładam produkt %d do bufora .\n", produkt);
        sleep(random()%5);
        //bufor=produkt;   //<-odkomentowac
        printf(" Skonczylem :)\n");
        pthread_mutex_unlock(&konsument_mutex);
    }
}

void *konsument (void *arg){
int x, i, produkt;

    for (i=0;i<=10;i++) {
        pthread_mutex_lock(&konsument_mutex);
        produkt=bufor;  //<-zakomentowac
        printf("Konsument : Konsumuje produkt %d z bufora .\n", produkt);
        sleep(random()%5);
        //produkt=bufor;   //<-odkomentowac
        printf(" Skonczylem :)\n\n");
        pthread_mutex_unlock(&producent_mutex);
    }
}

Zdziwiła mnie mocno jedna rzecz. Program w postaci jak powyzej dziala prawidlowo tzn. watek producent umieszcza produkt w buforze, a gdy skoncz, umozliwia watkowi konsument pobranie wartosci z bufora. Wynik:

Producent : Wkładam produkt 38 do bufora .
 Skonczylem :)
Konsument : Konsumuje produkt 38 z bufora .
 Skonczylem :)

Producent : Wkładam produkt 12 do bufora .
 Skonczylem :)
Konsument : Konsumuje produkt 12 z bufora .
 Skonczylem :)

Gdy zakomentuje sie linie oznaczone przez "<-zakomentuj" i odkomentuje te oznaczone przez "<-odkomentuj" program przestaje dzialac prawidlowo. Wynik:

Producent : Wkładam produkt 32 do bufora .
 Skonczylem :)
Konsument : Konsumuje produkt 1073962240 z bufora .
 Skonczylem :)

Producent : Wkładam produkt 53 do bufora .
 Skonczylem :)
Konsument : Konsumuje produkt 32 z bufora .
 Skonczylem :)

Za każdym razem przypisywanie/odczytywanie danych z bufora jest przed odblokowaniem mutexu dla konsumenta/producenta, dlatego nie rozumiem dlaczego robi to różnicę...
Moze ktos mi wyjasnic dlaczego tak się dzieje?

Pozostało 580 znaków

2005-12-07 12:18
0

dlatego ze wyswietlanie wartosci zmiennej produkt bedzie wczesniej niz jej zmodyfikowanie:
/bufor=produkt; <- tutaj by bylo prawidlowo bo jest zmodyfikowane przed wyswietleniem /
/ wyswietlenie wartosci zmiennej produkt /
printf("Producent : Wkładam produkt %d do bufora .\n", produkt);
sleep(random()%5);
/ jak widac tutaj dopiero jest zmodyfikowana wiec ta wartosc zostanie wyswietlona dopiro przy nastepnym przejsciu petli for /
bufor=produkt;
wszystko ;)
hmm i troche dziwnie rozwiazales to blokowanie poprzez mutex'a powinno byc raczej zrealizowane dla konkeretnego watrku a nie tak na przemian bo to jest strasznei mylace mutex jak wiesz mzoe byc przechwycony tylko dla jednego watku w tym samym czasie dodatkowo niepotrzebnie zmienne lokalne stosujesz jak sa one zbedne wiec lepij to bedzie wygladac jak zrobisz tak:

//globalne
pthread_mutex_t wspolny_mutex=PTHREAD_MUTEX_INITIALIZER;
int bufor;

//fragment main()
int main () {
...

        pthread_create(&producent_t, NULL, producent, &x);
        pthread_create(&konsument_t, NULL, konsument, &x);
...
}

void *producent (void *arg){
int i;
        for (i=0;i<=10;i++) {
                pthread_mutex_lock(&wspolny_mutex);
                bufor=random()%100; 
                printf("Producent : Wkładam produkt %d do bufora .\n", bufor);
                sleep(random()%5);
                printf(" Skonczylem :)\n");
                pthread_mutex_unlock(&wspolny_mutex);
        }
}

void *konsument (void *arg){
int i;

        for (i=0;i<=10;i++) {
                pthread_mutex_lock(&wspolny_mutex);
                printf("Konsument : Konsumuje produkt %d z bufora .\n", bufor);
                sleep(random()%5);
                printf(" Skonczylem :)\n\n");
                pthread_mutex_unlock(&wspolny_mutex);
        }
}

programming is the source of our life...

Pozostało 580 znaków

2005-12-07 14:43
0

OK to juz wiem dlazcego zle sie wyswietlalo :) glupi blad [sciana]

Ale jeszcze sie odwolam do Twojej propozycji z jednym mutexem. A co w sytuacji, gdy powiedzmy proces producent roznych przyczyn zamarudzi troche w wykonywaniu swojej funkcji i konsument bedzie pobieral kilka razy ta sama wartosc bufora, lub producent bedzie dzialal duzo szybciej od konsumenta i bedzie wpisywal do bufora kilka wartosci zanim konsument je odczyta...

Moze wystapic tez krytyczny przypadek, ze konsument po starcie programu pierwszy dostanie sie do mutexa i pobierze wartosc bufora, ktorej jeszcze nie ustalil producent.

Chyba nie zaznaczylem wczesniej ze watki musza byc zsynchronizowane w zapisywaniu/odczytywaniu bufora.

Pozostało 580 znaków

2005-12-07 15:04
0

no to sa zsynchronizowane przeciez jak juz wspomniaem tylko jeden watek moze w danym momencie przechwycic mutexa jezeli drugi watek bedzie chcial w tym samym czasie to zrobic to bedzie zatrzymany w miejscu wywolania lock dopoki watek ktory przechwycil mutexa go nie zwolni odnoszac sie do Twojego przykladu takie sytuacje ktore opisales nie zajda poniewaz Ty uruchamiasz w pierwszej kolejnosci watek producenta a dopiero pozniej konsumenta a wiec watek producenta jako pierwszy przechwyci zawsze mutexa takze kolejnosc zawsze bedzie zachowana:

producent:
1.przechwytuje(blokuje) mutexa jesli mutexa przechwycil konsument czeka w tym miejscu
2.modyfikuje zawartosc bufora
3.zwalnia mutexa

konsument
1.przechwytuje(blokuje) mutexa jesli mutexa przechwycil producent czeka w tym miejscu

  1. odczytuje zawartosc bufora
  2. zwalnia mutexa

proste


programming is the source of our life...

Pozostało 580 znaków

2005-12-07 15:11
0

Nie zrozumielismy sie chyba...

Jeden mutex nie wyklucza sytuacji, w ktorej konsument lub producent dwa razy z rzedu dziala na buforze, a cos takiego nie moze wystapic. Dlatego uwazam ze jeden mutex jest w tym momencie niewystarczajacy.

Pozostało 580 znaków

2005-12-07 15:45
0

wodzil slepy kulawego...
ale nie moga! dzialac w tym smaym momencie skoro operacje na miznnej bufor zachodza dopiero po przechwyceniu mutexa jesli producent przechwycil mutexa to konsument go nie prechwyci dopoki producent tego mutexa nie zwolni... Ty mylisz troszke zasade dzialania zawsze ktorys watek przechwyci jako pierwszy skoro jeden zakonczyl dzialanie i zwolnij a drugi czekal w kolejce na to zeby poprzedni watek zwolnij mutexa przechwyci go jako nastepny to jest jak kolejka w ktorej ustawiaja sie kandydaci... a skoro producent jest tworzony jako pierwszy w main on pierwszy przechwyci mutexa i zacznie ta cala procedure a konsument nastepny pozniej znow producent itd patrz diagram ktory podalem wyzej jasno przedstawia jak to bedzie sie zachowywac... wiec nie wiem gdzie Ty masz swoej watpliwosci...

//edit
zreszta Ty robisz dokladne ta sama operacje zapomnialem dodac Tobie tylko ze na 2 mutexach a przejrzysciej jest na jednym po prostu ten 1 jest zbedny i wprowadza niepotrzebne zamieszanie


programming is the source of our life...

Pozostało 580 znaków

2005-12-07 18:44
0

Zauwaz ze producent najpierw blokuje producent_mutex, a po wykonaniu operacji na buforze odblokowuje konsument_mutex, wiec gdy bedzie probowal po raz drugi z rzedu pisac do bufora to nie bedzie mogl tego zrobic. Dopiero jak konsument odczyta wartosc i zwolni mu producent_mutex stanie sie to mozliwe. Z konsumentem jest odwrotnie - wykonujac swoja funkcje najpierw blokuje konsument_mutex a potem odblokowuje producent_mutex. To zapewnia, ze producent nie zapisze w buforze nowej wartosci dopoki konsument jej nie odczyta.

Pozostało 580 znaków

2005-12-07 20:12
0
mcveat napisał(a)

Zauwaz ze producent najpierw blokuje producent_mutex, a po wykonaniu operacji na buforze odblokowuje konsument_mutex, wiec gdy bedzie probowal po raz drugi z rzedu pisac do bufora to nie bedzie mogl tego zrobic. Dopiero jak konsument odczyta wartosc i zwolni mu producent_mutex stanie sie to mozliwe. Z konsumentem jest odwrotnie - wykonujac swoja funkcje najpierw blokuje konsument_mutex a potem odblokowuje producent_mutex. To zapewnia, ze producent nie zapisze w buforze nowej wartosci dopoki konsument jej nie odczyta.

dla mnie to co napisalem wyzej jest prostsze i wykonuje to samo ale skoro mowisz ze nie to rob po swojemu chcialem wskazac tylko prawidlowe zastosowanie mutexa bo na tym wlasnie polega stosuje sie jeden mutex i on zapewnie prawidlowy dostep do zwartosci wylacznie dla danego watku w danym czasie...

//Faszczu:
//Maker - zacznij ty stosowac znaki interpunkcyjne bo sie mozna pociac jak sie czyta twoje posty.


programming is the source of our life...

Pozostało 580 znaków

2005-12-08 20:35
0

Skorzystaj z CriticalSection. Szybka i łatwa w impementacji.

Pozostało 580 znaków

2005-12-13 13:57
0
Maker napisał(a)

odnoszac sie do Twojego przykladu takie sytuacje ktore opisales nie zajda poniewaz Ty uruchamiasz w pierwszej kolejnosci watek producenta a dopiero pozniej konsumenta a wiec watek producenta jako pierwszy przechwyci zawsze mutexa

Jesteś aby pewien tego co piszesz? Sprawdzałeś to różnych komputerach / różnych systemach?
Masz to gdzieś w specyfikacji?

To, że jakiś wątek uruchomisz wcześniej nie zagwarantuje, że dostanie on mutex jako pierwszy. Ta decyzja zostaje w gestii schedulera systemu operacyjnego. Na jednym systemie może działać, na innym pewnie nie będzie. Jeśli chcesz mieć kłopoty w nieprzewidzianych momentach to koduj w oparciu o takie "mądrości ludowe". :>

W Twoim sposobie może się zdarzyć, że konsument będzie próbował odczytać niezapisany bufor. Może się też zdarzyć, że producent zapisze bufor dwukrotnie zanim konsument go odczyta.

Sposób mcveat z dwoma mutexami NIE JEST równoważny Twojemu sposobowi. Jest nieco zakręcony, ale POPRAWNY. Tego typu dostęp można też realizować na monitorach (pthread_cond_xxxx). Przykład jest w manualu (man pthread_cond_init).

Pozostało 580 znaków

2005-12-13 14:13
0

no raczej z tego co ja wiem akurat to watki i procesy o tym samym priorytecie a tak jest w tym wypadku sa uruchamiane/ponawiane w pierwszej kolejnosci te ktore czekaly najdluzej i jestem raczej pewien ze ten watek ktory utworzysz jako pierwszy w danym procesie bedzie startowal jako pierwszy poniewaz jest to wywolanie funkcji tworzacej, kolejny watek jest tworzony z pewnym opoznieniem. Ten ktory zostal wywolany jako pierwszy logiczne ze nie bedzie czekal az laskawie kolejny zostanei utworzony i wystartuje ;] zreszta skad ma niby to wiedziec troche dziwnie przedstawiles swoja hipoteze ;)
i roznych komputerach lal od kiedy o kolejnosci watkow decyduje sprzet?:D myslalem ze o tym decyduje system operacyjny ale widze ze wysnuwasz nowe "madrosci ludowe" ;]


programming is the source of our life...

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0