2017-02-13 77 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系统时,你了解与特定实现相关的所有问题,如严格的不受控制的循环,重绘,闪烁等。 –