C#锁紧螺纹

C#锁紧螺纹,c#,multithreading,C#,Multithreading,我目前正在尝试阅读一些关于C中线程锁定的文章# 如果我有一个类似下面的类 public class Connection { bool Connected; internal bool startConnection(Device dev) { // start connection Connected = true; } internal bool endConnection(Device dev) {

我目前正在尝试阅读一些关于C中线程锁定的文章#

如果我有一个类似下面的类

public class Connection
{
    bool Connected;
    internal bool startConnection(Device dev)
    {
       // start connection
       Connected = true;
    }

    internal bool endConnection(Device dev)
    {
       // End connection
       Connected = false;
    }

    private void readFromConnected(Device dev)
    {
        if(Connected)
        {
            // read values from connected device
        }
    }
}
我现在的问题是,我有多个线程使用这个类从不同的设备读取值

当一个线程在实际断开连接时尝试读取值,但由于另一个线程将连接的bool保持为true而尝试读取值时,就会出现问题

调用此类的线程如下所示

Device deviceReceived;
public PollingInstance(Device deviceSent)
    {
        deviceReceived = deviceSent;
        aTimer = new System.Timers.Timer(2500); //1000 = 1 sec
        aTimer.Elapsed += OnTimedEvent;
        aTimer.Enabled = true;
    }


 private void OnTimedEvent(Object source, ElapsedEventArgs e)
 {
     for (int i = 0; i < 10; i++)
     {
        Connection.startConnection(deviceReceived);
        Connection.readFromConnected(deviceReceived);
        Connection.endConnection(deviceReceived);
     }
 }

很难说会发生什么,因为您发布的代码甚至不会编译

你不想这样:

private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
    Connection connection = whereverThisComesFrom();
    if(!Monitor.TryEnter(connection))  return; // another timer is in progress
    try
    {
      for (int i = 0; i < 10; i++)
      {
         connection.startConnection(deviceReceived);
         connection.readFromConnected(deviceReceived);
         connection.endConnection(deviceReceived);
      }
    }
    finally
    {
      Monitor.Exit(connection);
    }
}
private void OnTimedEvent(对象源,ElapsedEventArgs e)
{
Connection Connection=whereverThisComesFrom();
如果(!Monitor.TryEnter(connection))返回;//另一个计时器正在运行
尝试
{
对于(int i=0;i<10;i++)
{
连接。启动连接(设备接收);
连接。readFromConnected(deviceReceived);
连接。端连接(deviceReceived);
}
}
最后
{
监控。退出(连接);
}
}

很难说会发生什么,因为您发布的代码甚至无法编译

你不想这样:

private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
    Connection connection = whereverThisComesFrom();
    if(!Monitor.TryEnter(connection))  return; // another timer is in progress
    try
    {
      for (int i = 0; i < 10; i++)
      {
         connection.startConnection(deviceReceived);
         connection.readFromConnected(deviceReceived);
         connection.endConnection(deviceReceived);
      }
    }
    finally
    {
      Monitor.Exit(connection);
    }
}
private void OnTimedEvent(对象源,ElapsedEventArgs e)
{
Connection Connection=whereverThisComesFrom();
如果(!Monitor.TryEnter(connection))返回;//另一个计时器正在运行
尝试
{
对于(int i=0;i<10;i++)
{
连接。启动连接(设备接收);
连接。readFromConnected(deviceReceived);
连接。端连接(deviceReceived);
}
}
最后
{
监控。退出(连接);
}
}
你说过:

当一个线程试图在其运行时读取值时,会出现一个问题 实际上已断开连接,但仍尝试读取值,因为 另一个线程将连接的bool保持为true

您能否使用try/finally来确保正确设置布尔值

lock
关键字相当于监视器try/finally

object syncObject = new object();
Monitor.Enter(syncObject);
try {
    // Code updating shared data
}
finally {
    Monitor.Exit(syncObject);
}

object syncObject = new object();
lock (syncObject) {
// Code updating shared data
}
你说:

当一个线程试图在其运行时读取值时,会出现一个问题 实际上已断开连接,但仍尝试读取值,因为 另一个线程将连接的bool保持为true

您能否使用try/finally来确保正确设置布尔值

lock
关键字相当于监视器try/finally

object syncObject = new object();
Monitor.Enter(syncObject);
try {
    // Code updating shared data
}
finally {
    Monitor.Exit(syncObject);
}

object syncObject = new object();
lock (syncObject) {
// Code updating shared data
}

简单。为什么
连接到
a
bool

试试这个

public class Connection
{
    private int _connections = 0;
    internal bool startConnection(Device dev)
    {
       // start connection
       if(Interlocked.Increment(ref _connections) == 1)
       {
          //do work to connect.
       }
    }

    internal bool endConnection(Device dev)
    {
       // End connection
       if(Interlocked.Decrement(ref _connections) == 0)
       {
          //do work to disconnect.
       }
    }

    private void readFromConnected(Device dev)
    {
        if(_connections > 0)
        {
            // read values from connected device
        }
    }
}
这将“工作”的一些价值观的工作。但由于异常和草率/健忘的编程,很容易导致连接处于打开状态。因此,我建议如下

Device device = ...
using(var connection = device.CreateConnection())
{
    var results = connection.Read();
}

public abstract class Connection : IDisposable
{
    public object Read();
}

public class Device
{
    private class DeviceConnection : Connection 
    {
        private Device Parent { get; set; }

        void Dispose()
        {
            Parent.StopConnection();
        }
        public object Read() 
        {
            return Device.readFromConnected();
        }
    }        

    private int _connections = 0;
    public Connection CreateConnection()
    {
       // start connection
       if(Interlocked.Increment(ref _connections) == 1)
       {
          //do work to connect.
       }
       return new DeviceConnection { Parent = this };
    }

    private bool StopConnection()
    {
       // End connection
       if(Interlocked.Decrement(ref _connections) == 0)
       {
          //do work to disconnect.
       }
    }

    private object readFromConnected()
    {
        //Device is guaranteed to be connected now!
    }
}

简单。为什么
连接到
a
bool

试试这个

public class Connection
{
    private int _connections = 0;
    internal bool startConnection(Device dev)
    {
       // start connection
       if(Interlocked.Increment(ref _connections) == 1)
       {
          //do work to connect.
       }
    }

    internal bool endConnection(Device dev)
    {
       // End connection
       if(Interlocked.Decrement(ref _connections) == 0)
       {
          //do work to disconnect.
       }
    }

    private void readFromConnected(Device dev)
    {
        if(_connections > 0)
        {
            // read values from connected device
        }
    }
}
这将“工作”的一些价值观的工作。但由于异常和草率/健忘的编程,很容易导致连接处于打开状态。因此,我建议如下

Device device = ...
using(var connection = device.CreateConnection())
{
    var results = connection.Read();
}

public abstract class Connection : IDisposable
{
    public object Read();
}

public class Device
{
    private class DeviceConnection : Connection 
    {
        private Device Parent { get; set; }

        void Dispose()
        {
            Parent.StopConnection();
        }
        public object Read() 
        {
            return Device.readFromConnected();
        }
    }        

    private int _connections = 0;
    public Connection CreateConnection()
    {
       // start connection
       if(Interlocked.Increment(ref _connections) == 1)
       {
          //do work to connect.
       }
       return new DeviceConnection { Parent = this };
    }

    private bool StopConnection()
    {
       // End connection
       if(Interlocked.Decrement(ref _connections) == 0)
       {
          //do work to disconnect.
       }
    }

    private object readFromConnected()
    {
        //Device is guaranteed to be connected now!
    }
}


这是否意味着您需要一个
ConcurrentDictionary
来分别跟踪每个设备的连接状态?@M.kazemAkhgary这是一个输入错误。C#不会让你这么做的。是的,我想写的是如果(连接),但我的头在云端的那一刻有多个设备应该可以独立使用?介意我问一下你在建什么吗?这些设备是什么?这是否意味着您需要一个
ConcurrentDictionary
来分别跟踪每个设备的连接状态?@M.kazemAkhgary这是一个输入错误。C#不会让你这么做的。是的,我想写的是如果(连接),但我的头在云端的那一刻有多个设备应该可以独立使用?介意我问一下你在建什么吗?这些设备是什么?使用
TryEnter
而不只是执行锁定的目的是防止在回调仍在进行时触发计时器时发生线程泄漏。可以通过简单计数已初始化/取消初始化类的线程来解除锁定。它还将线程安全的负担放在调用代码中,最危险的地方。使用
TryEnter
而不只是执行锁定的目的是防止在回调仍在进行时触发计时器时线程泄漏。可以通过简单的初始化/取消初始化类的线程计数来解除锁定。它还将线程安全的负担放在调用代码中,这是最危险的。如果在连接过程中调用另一个调用时调用了
CreateConnection
,则可能最终得到一个连接,该连接认为它已连接,而实际上它并没有连接。您还假设
readFromConnected
是线程安全的,如果设备实际上是一个“设备”,则可能不是这种情况。除了使用dispose模式处理这类事情外,这是一条可行之路。@Yaur的所有优点都很好。但是现在我纠正已经太晚了。我现在在床上。感谢大家的帮助,所有这些回复都给了我一个解决这个问题的想法,但需要先进行测试。如果在连接过程中调用了
CreateConnection
,而另一个调用正在进行连接,那么您可能会得到一个连接,该连接认为它已连接,而实际上并没有连接。您还假设
readFromConnected
是线程安全的,如果设备实际上是一个“设备”,则可能不是这种情况。除了使用dispose模式处理这类事情外,这是一条可行之路。@Yaur的所有优点都很好。但是现在我纠正已经太晚了。我现在在床上。感谢大家的帮助,所有这些回复都给了我一个解决这个问题的想法,但需要先测试。