Niespełniający zadania warunek if

0

Witam,
Mam dwa wątki, każdy w innej klasie. Jeden jest wykonywany przez cały czas, drugi to timer. Oba ,,zgarniają" dane ze strumienia, ale na czas działania timera nasłuchiwanie z drugiego wątku powinno być wyłączone. Żeby to osiągnąć, napisałem coś takiego:
Wątek 1:

static void listen()
        {
            while(true)
            {
                if (Listen) // Warunek, który powinien spowodować poprawne działanie programu
                {
                    try
                    {
                        string msg = Reader.ReadString();
                        //...
                    }
                    catch {//...}
                }
                Thread.Sleep(100); // Odczekujemy czas
            }
        }

Timer

private void timer1_Tick(object sender, EventArgs e)
        {
            Class2.Listen = false; //Wyłączamy nasłuchiwanie z drugiego wątku
            //...
            string list = Class2.Reader.ReadString(); // Pobieramy dane ze strumienia | punkt zatrzymania się programu
            //...
            Class2.Listen = true; // Z powrotem włączamy nasłuchiwanie z drugiego wątku
        }

Nie mam pojęcia czemu, ale za wykonaniem timer1_Tick wszystko idzie jak powinno, ale za drugim razem warunek if z drugiego wątku jakoś zostaje pominięty, a dane są zbierane przez dalsze instrukcje zamiast przez timer. Nie mam pojęcia co powinienem zrobić. Debuggerem upewniłem się, że program zatrzymuje się w miejscu oznaczonym w kodzie, a drugi wątek zbiera dane mimo iż Listen jest ustawione na false. Co może iść nie tak?

1

Instrukcja "if" nie zagwarantuje Ci synchroniczności w wątkach. Przykład: jesteś w linijce try... kiedy ustawiasz flagę Listen na false. Później z obu wątków jest czytany Reader ponieważ drugi wątek był już po sprawdzeniu warunku. Użyj do tego problemu najprostszej możliwej opcji jakim jest lock. Thread.Sleep jest niepotrzebny.

0

Też na to wpadłem, więc na początku ,,na Janusza" przy każdej linijce w pierwszym wątku dodałem sprawdzanie flagi Listen ;) Niestety

lock(Client.Reader)

nie zadziałało i problem pozostał...

0
gogolon napisał(a):

Też na to wpadłem, więc na początku ,,na Janusza" przy każdej linijce w pierwszym wątku dodałem sprawdzanie flagi Listen ;)

Nawet i to nie ma prawa działać poprawnie. Bo może się if sprawdzić instrukcję przed znegowaniem flagi i cała logika

gogolon napisał(a):

przy każdej linijce
poszła w pizdu :P

public object lockObj = new object();

static void listen()
        {
            while(true)
            {
                lock (lockObj)
                {
                    try
                    {
                        string msg = Reader.ReadString();
                        //...
                    }
                    catch {//...}
                }
            }
        }
private void timer1_Tick(object sender, EventArgs e)
        {
            lock (Class2.lockObj)
            {
                string list = Class2.Reader.ReadString(); // Pobieramy dane ze strumienia | punkt zatrzymania się programu
            }
        }

Pisane z pamięci może być literówka. Nie działa?

0

Nie wiem czy dobrze rozumiem działanie lock. Ta instrukcja blokuje dostęp do obiektu innym wątkom tak? Jeśli tak to działa, to potrzebuję zablokować z poziomu timera dostęp do obiektu Reader drugiemu wątkowi. Więc piszę sobie coś takiego:

private void timer1_Tick(object sender, EventArgs e)
        {          
            lock(Class2.Reader)
            {
             //...
            }
        }

Dodaję też lock w drugim wątku.
Ale to nie pomaga, więc podejrzewam że źle używam tego operatora. Użyłem też Twojego kodu, rezultat podobny, czyli... żaden :P
Tak na wszelki, doprecyzuję co chcę uzyskać - podczas działania funkcji timer1_Tick drugi wątek ma się ,,zatrzymywać", żeby nie zebrać danych ze strumienia, które powinny trafić do wątku z timerem. Próbowałem wszystkiego co wymyśliłem, łącznie z wywoływaniem Abort() na drugim wątku a potem jego startowaniem na nowo. Nic nie zadziałało ;/

1

Twierdzisz, że w obu wątkach na raz jesteś w środku klamer lock'a (czyt. sekcji krytycznej)? Jeśli tak to robisz to źle więc chyba najlepszą metodą będzie wrócić do programów konsolowych i przetestować sobie działanie różnych metod synchronizacji wątków.

Do testów napisałem Ci schemat dla lock'a (jest więcej różnych metod - po resztę odsyłam do dokumentacji):

public class Hello
    {
        public object objLock = new object();

        public void Test(string name)
        {
            while (true)
                lock (objLock)
                    for (int a = 1; a <= 10; a++) //tutaj nigdy nie będziesz w wielu wątkach na raz
                        Console.WriteLine(string.Format("Hello {0} #{1}", name, a)); //tutaj nigdy nie będziesz w wielu wątkach na raz
        }
    }
//w Main
Hello sec = new Hello();

            Thread firThr = new Thread(() => sec.Test("firThr"))
            {
                IsBackground = true
            };

            Thread secThr = new Thread(() => sec.Test("secThr"))
            {
                IsBackground = true
            };

            firThr.Start();
            secThr.Start();

Pozbyłem się zbędnych klamr w metodzie Test byś lepiej mógł zaobserwować jakie magiczne rzeczy się tam dzieją. Daj znać jak przeplotą Ci się instrukcje for między wątkami.

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