【发布时间】:2014-05-09 19:05:50
【问题描述】:
最后,我收到线程无法访问,因为它由另一个线程拥有。但是,这与 UI 无关(直接)。仅当我尝试设置对象的属性而不是成员本身时才会引发异常。如果我直接设置成员,它工作正常,但我失去了我的 PropertyChanged 事件。 请,如果我过于复杂了,请告诉我!我想不出其他方式将属性返回到 MainWindow。
您可以快进到下面的第 3 类查看结果。在最高级别,我涉及三个类:MainWindow、OCXComms 和 ZServer。当按下监听按钮时,它会调用 OCXComms 中的启动方法并负责创建 ZServer 实例,如下所示:
第 1 类
public partial class MainWindow : Window
{
private OCUComms comms;
......
private void roxListenBtn_Click(object sender, RoutedEventArgs e)
{
//Debugger Shows Main Thread
comms.StartOutput();
}
void comms_IsClientConnectedChanged(object sender, PropertyChangedEventArgs e)
{
connectionStatusLbl.Content = "Connected - No Control";
connectionStatusLbl.Foreground = myWarningBrush;
roverControlBtn.IsEnabled = true;
manualControlRB.IsEnabled = true;
}
......
}
接下来,通过 StartOutput 在“MainThread”上构造 ZServer 对象。这很好用。
第 2 类
public sealed class OCXComms : INotifyPropertyChanged
{
private static OCXComms instance;
private static readonly object instanceSync = new object();
private Boolean _isClientConnected = false;
private bool isEnabled;
.....
public static OCXComms Instance
{
get
{
if (instance == null)
{
lock (instanceSync)
{
if (instance == null)
instance = new OCXComms();
}
}
return instance;
}
}
private OCXComms()
{
isEnabled = false;
_isControllerEnabled = false;
_isKeyboardEnabled = false;
worker = new System.Timers.Timer();
worker.Elapsed += new ElapsedEventHandler(worker_Elapsed);
Properties.Settings.Default.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Default_PropertyChanged);
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnClientConnectedChanged()
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("IsClientConnected"));
}
void server_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.IsClientConnected = server.getIsClientConnected();
}
public void StartOutput()
{
if (isEnabled)
return;
Console.WriteLine("ZServer started on: " + Thread.CurrentThread.Name);
//Debugger Shows Main Thread
this.server = new ZServer(Properties.Settings.Default.ListeningPort);
this.server.PropertyChanged += server_PropertyChanged;
this.server.Start();
IsEnabled = true;
}
}
这就是问题所在。请注意两种不同的尝试(仅在此处显示,实际上并未在语法中显示)。如果没有断点,客户端和服务器就会挂起,如果设置了断点,则第一个更改异常会通知我一个线程正在尝试访问另一个线程拥有的信息。我很清楚 ZServer 是在“MainThread”上创建的,此时我在侦听器线程上。我毫不怀疑这是问题所在。但是,我不确定如何进行。我的大部分研究都指向 Dispatcher,但我不在它的主窗口中……“我深三类;)”我尝试过锁定、监控、新线程,但都没有成功。任何建议将不胜感激!
第 3 类
public class ZServer
{
private Thread listenThread;
private Boolean _isClientConnected = false;
public ZServer(String sIP, int iPort)
{
InitializeServer(sIP, iPort);
}
private void InitializeServer(String sIP, int iPort)
{
this.tcpListener = new TcpListener(IPAddress.Parse(sIP), iPort);
this.listenThread = new Thread(new ThreadStart(ListenForClients_DoWork));
this.listenThread.Name = "Listen Thread";
}
public Boolean IsClientConnected
{
get
{
return _isClientConnected;
}
private set
{
_isClientConnected = value;
OnClientConnectedChanged();
}
}
private void OnClientConnectedChanged()
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("IsClientConnected"));
}
private void ListenForClients_DoWork()
{
// Start the Server Listening for Clients to connect while blocking.
this.tcpListener.Start();
while (!tokenSource.Token.IsCancellationRequested)
{
try
{
TcpClient client = this.tcpListener.AcceptTcpClient();
this._isClientConnected = true; //<== This Works
this.IsClientConnected = true; //This causes client and server to hang. Possible deadlock?
........
}
catch (SocketException socketEx)
{
Console.WriteLine("Socket Closed from Another Thread: " + socketEx.ToString());
}
catch (Exception ex)
{
Console.WriteLine("ZServer: unhandled exception in ListenForClients: " + ex.Message);
}
}
Console.WriteLine("ListenForClients exiting...");
}
public Boolean getIsClientConnected()
{
lock (_clientConnectedLock)
{
return _isClientConnected;
}
}
}
【问题讨论】:
标签: c# multithreading properties locking polymorphism