2017-02-13 114 views
0

我目前正在一個項目中接收幀作爲bytearray並將它們顯示在GUI(WPF)上。現在我不滿意這個表現,因爲這些幀會延遲顯示。 所以我想到做多線程,以便套接字和GUI工作彼此獨立。但是,如果我嘗試在一個單獨的線程中運行socketRoutine,我得到一個錯誤,一個線程不能訪問另一個線程的資源。C#在線程之間傳遞數據很容易

林不知道哪個資源是指。我猜它可能是傳遞給GUI的bytearray或其必須訪問的GUI組件。

這些是我現在的代碼。

namespace Subscriber_WPF{ 
/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
/// 

public partial class MainWindow : Window{ 

    /*Kinect Datentypen*/ 
    private WriteableBitmap colorBitmap = null; 
    static readonly String publisherID = "TYPE1"; 

    SocketHandler socketHandler; 
    Thread socketThread; 

    public MainWindow(){  
     ConsoleManager.Show(); 
     colorBitmap = new WriteableBitmap(1920, 1080, 96.0, 96.0, PixelFormats.Bgra32, null); 
     this.DataContext = this; 

     //initializeKinectComponents(); 
     socketHandler = new SocketHandler(5555, publisherID, this); 
     socketThread = new Thread(()=>socketHandler.runSocketRoutine()); 

     Console.WriteLine("GUI-Components initialized. Press Enter to start receiving Frames."); 

     this.KeyDown += MainWindow_KeyDown; 

    } 

    private void MainWindow_KeyDown(object sender, KeyEventArgs e){ 
     if (e.Key.Equals(Key.Return)) { 
      socketThread.Start(); 
     } 
    } 

    public void refreshGUI(byte[]content) { 
     Action EmptyDelegate = delegate() { }; 
     BitmapSource source = BitmapSource.Create(1920, 1080, 72, 72, PixelFormats.Bgra32, BitmapPalettes.Gray256, content, 1920 * 4); 
     videoView.Source = source; 

     /*interrupt the socket-Loop to update GUI=> that is the current method without multithreading*/ 
     //this.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); 

    } 


} 

的SocketHandler

namespace Subscriber_WPF{ 

class SocketHandler{ 

    private int port; 
    private string publisherID; 
    private MainWindow window; 
    private static ZContext context; 
    private static ZSocket subscriber; 

    public SocketHandler(int port, string publisherID, MainWindow window) { 
     this.port = port; 
     this.publisherID = publisherID; 
     this.window = window; 
     this.initializeZMQSocket(this.port, this.publisherID); 
    } 

    private void initializeZMQSocket(int port, String publishID){ 
     context = new ZContext(); 
     subscriber = new ZSocket(context, ZSocketType.SUB); 
     /*initialize sockets*/ 
     subscriber.Connect("tcp://127.0.0.1:" + port); 
     subscriber.Subscribe(publishID); 
     Console.WriteLine("subscriber is ready!"); 
    } 


    public void runSocketRoutine(){ 
     Console.WriteLine("Waiting for Messages."); 

     while (true) 
     { 
      byte[] content = new byte[8294400]; 

      using (ZMessage message = subscriber.ReceiveMessage()) 
      { 
       Console.WriteLine("Message received!"); 
       string pubID = message[0].ReadString(); 
       /**/ 
       if (pubID.Equals(publisherID)) 
       { 

        content = message[1].Read(); 
        Console.WriteLine("size of content: " + message[1].Length); 
        window.refreshGUI(content); 
       } 

      } 
     } 

    } 


} 

如果有人有關於如何停止拖延顯示器或我怎麼能輕易搞定線程問題,我將非常感激的想法!

很多問候!

+1

我想你嘗試從另一個線程比MainThread = UIThread更新UI。你必須使用'Dispatcher.Invoke'http://stackoverflow.com/questions/4253088/updating-gui-wpf-using-a-different-thread – Mat

+0

[使用不同的線程更新GUI(WPF)]的可能重複( http://stackoverflow.com/questions/4253088/updating-gui-wpf-using-a-different-thread) – Mat

+3

因此,您經常重新創建一個1920 x 1080的位圖來顯示並思考性能問題?也許你應該找到一種不同的方式來呈現你的視覺數據。 – grek40

回答

2

我在過去使用優秀的RX framework做過類似的事情。您的運行套接字例程變爲IObservable,其中T是您返回的類型,在您的情況下爲byte []。然後你可以在UI線程上訂閱這個流。使用RX框架,你也可以做一些很酷的事情,比如速率限制,所以如果你的例程吐出大量的「記錄」,你可以將它限制爲每個時間段1個。

+0

這不會解決重繪問題。它會使重繪更平滑,但它仍然需要大量的CPU。 –

+1

真的,它仍然會問很多的CPU,但通過速率限制訂閱,你可以找到CPU使用率和視覺重繪速度之間的折衷 –

+0

@HenkHolterman抱歉,當你使用近實時GIS系統時,你瞭解與特定實現相關的所有問題,如嚴格的不受控制的循環,重繪,閃爍等。 –