C# da Thread Çakışmaları nasıl önlenir?

Başlatan Mucit23, 16 Kasım 2019, 23:08:51

Mucit23

Selamlar

Yaptığım uygulamalarda Bilgisayar haberleşmesi gereken uygulamalarda C# kullanıyorum. Çok fazla bilgim yok sadece işimi görecek kadar basit seviyede biliyorum C#'ı. Bu sorunla daha önce karşılaşmıştım. Fakat Bu sefer birden fazla Thread çakışması oluyor. 

Bir uygulama için Seri Port üzerinden String alıyorum. Bu string üzerinde bir takım işlemler yapıp Grafik olarak göstermem gerekiyor. Aynı zamanda gelen string üzerinde bir takım işlemler yapıp çeşitli textbox'lara yazmam gerekiyor. Buna benzer birkaç farklı işlem yapmam gerektiğinde bir olay bitmeden yada bir olayın içerisinde başka nesneye ulaşmak istersem thread çakışması yaşanıyor.

Seri Port için DataRecieved olayı oluştuğunda string'i alıyorum. Daha sonra sıralı olarak bir takım işlemler yapmam gerekiyor. Örnek veriyorum gelen veriyi TextBox'da göstereyim ve Gelen sitringi ayrıştırıp grafiğini çizeyim.

Bunun için Nasıl bir yol izlemek gerekir?

tunayk

Çakışmaları önlemek için çeşitli yöntemler mevcut. İşlemcide ki state machine mantığı gibi bir değişken üzerinden işlem sırasına göre hareket edersin.

Seriport olayına gelince, seriport Datareceived olayında gelen veri form ile aynı threadda olmadığından dediğin durum ortaya çıkar. Bu durumda ya string değişkene veriyi yazarsın, formdaki bir timer ile belli zamanlarda okuyarak gösterirsin. Bu şekilde gecikmeli ancak çakışmayan bir şekilde çalışırsın.

Daha iyi yol ise TextBox.Invoke() methodunu kullanmandır.


        delegate void SetTxt(string txt);
        void SetText(string txt)
        {
            if (textBox1.InvokeRequired)
            {               
                textBox1.Invoke(new SetTxt(SetText),new string[]{txt});                   
            }
            else textBox1.Text = txt;
        }
DataReceived olayında, TextBox'a yazmak istediğin texti SetText("yazılacak text") ile gönderebilirsin.


foseydon

@Mucit23

hocam timer kullan, datareceived ile uğraşma. ben bunun sebebini açıkladım başka yazılarda, bağlantı falan da var teknik bilgi okumak istersen. timer GUI thread'de çalışır, o yüzden thread'in yarattığı sıkıntılardan kurtulmuş olursun. datayı işlemek için yaptığın işlemler çok uzunsa, backgroundworker componenti ile hallet işlerini. o da threadsafe, işi bitince uyarıyor seni o zaman bastırırsın ekrana. ama ona gerek olacağını sanmam, timer ile çok rahat halledersin.

illa thread kullanacağım dersen "thread lock" diye arat araştır. şurda ufak bir örneği var:

https://www.c-sharpcorner.com/UploadFile/1d42da/thread-locking-in-C-Sharp/

thread çok opsiyonlu, bir sürü şey yapabilirsin. thread pool var, otomatik thread yönetimi için veya elle yönetebilirsin, bir thread'den başka thread spawn edebilirsin vs. vs. öğrenmen lazım değilse hiç bulaşma, dediğim gibi timer ile hallet ben bütün seri port işlerini timer ile yapıyorum sıkıntı yaşamadım.

Mucit23

Aslında bunun sebebi mikroişlemci mantığıyla kod yazmamdan kaynaklanıyor. Multi Tasking Thread Rtos yapılarına alışamadım gitti. Benim mantığım Data gelince Datayı parçalar, bir yerde göstereceksen göster sonra git grafik felan çiz şeklinde çalışıyor.

Ben sorunu şu şekilde çözdüm dün gece uğraşırken. DataRecieved olayı içinde istediğim fonksiyonu aşağıdaki gibi bir yapıyla çağırıyorum.

this.Invoke(new EventHandler(fonksiyon_ismi));

Bu şekilde istediğim fonksiyon için bir event oluşturuyorum. Fakat Timer kullanmakta mantıklı geldi. DataRecieved içinde veri geldimi veriyi global bir değişkene atıp, daha sonra timer event'i içinde veri gelmişse ise şunları yap desemde olabilirmiş.

OptimusPrime

Isletim sistemi uzerinde kod yazarken semaphore, counting semaphore, mutex, queue, mailbox vsvs gibi yapilari bilmiyorsan saclarin beyazlar  :D
https://donanimveyazilim.wordpress.com || Cihân-ârâ cihân içredir ârâyı bilmezler, O mâhîler ki deryâ içredir deryâyı bilmezler ||

power20

Thread çalışmasını önlemek için waitforsingleobject kullanılır.

Düzgün kullanılabilirse bir thread diğerini sabırla bekler. Çakışma olmaz

foseydon

Alıntı yapılan: Mucit23 - 17 Kasım 2019, 23:01:57Aslında bunun sebebi mikroişlemci mantığıyla kod yazmamdan kaynaklanıyor. Multi Tasking Thread Rtos yapılarına alışamadım gitti. Benim mantığım Data gelince Datayı parçalar, bir yerde göstereceksen göster sonra git grafik felan çiz şeklinde çalışıyor.

Ben sorunu şu şekilde çözdüm dün gece uğraşırken. DataRecieved olayı içinde istediğim fonksiyonu aşağıdaki gibi bir yapıyla çağırıyorum.

this.Invoke(new EventHandler(fonksiyon_ismi));

Bu şekilde istediğim fonksiyon için bir event oluşturuyorum. Fakat Timer kullanmakta mantıklı geldi. DataRecieved içinde veri geldimi veriyi global bir değişkene atıp, daha sonra timer event'i içinde veri gelmişse ise şunları yap desemde olabilirmiş.

Hocam o yaptığın kulağı tersten göstermek gibi oluyor. Benim yaptığım ve tavsiye ettiğim şu:
List<byte> serialportbuffer = new List<byte>();
if(serialPort.bytestoread > minimum framesize){
serialportbuffer.Add(serialport.readbyte())
}

Yazmaya üşendim hepsini, bir byte okuduğun için for çevirip hepsini tektek okuman lazım. Ben byte olarak okurum, bence en temizi. String yapmak istersen aynı mantık. Hiç datareceived ile falan uğraşma. Bundaki tek sıkıntı şu olabilir, çok veri alıyorsa timer süresi gelene kadar seri port Buffer i dolabilir. Ya timer aralığıni azaltirsin, ya seriport in inputbuffer özelliği var ordan daha yüksek bişey ayalarsin.

ahmet2017

Konu eski ve açıkçası karşıma da nerden çıktığını bilmiyorum.
Bir thread içerisinde farklı bir thread'e ait bir objeye ( fonksiyon , değişken vırt zırt ) erişmek ve üzerinde işlem yapmak isterseniz aşağıdaki yöntem ile cross-thread hatası almadan gerçekleştirebilirsiniz.

ahmet2017

this.Invoke(new MethodInvoker(delegate()
               {
                  // diger threaddeki degiskene objebe burada erisebilirsin.
               }));

mufitsozen

Alıntı yapılan: Mucit23 - 16 Kasım 2019, 23:08:51Selamlar
.........

Seri Port için DataRecieved olayı oluştuğunda string'i alıyorum. Daha sonra sıralı olarak bir takım işlemler yapmam gerekiyor. Örnek veriyorum gelen veriyi TextBox'da göstereyim ve Gelen sitringi ayrıştırıp grafiğini çizeyim.

Bunun için Nasıl bir yol izlemek gerekir?

En basiti threadler arasi haberlesme icin queue'ler ile haberlesin.

Zannediyorum simdi global data kullanarak haberlesiyorsunuz, bunun COK KOTU/HATA YARATAN bir metod oldugunu bilin.

Multithread uygulamalarda kullanan teknikleri kullanin, mutex, semaphor, critical section vb gibi.

Concurrency Cookbook CSharp
Aptalca bir soru yoktur ve hiç kimse soru sormayı bırakana kadar aptal olmaz.