2009-09-01 79 views
25

如何在不同线程之间共享数据在C#中不使用静态变量? 我们可以使用属性创建一个这样的机制吗?如何在不同线程之间共享数据在C#中使用AOP?

在这种情况下,面向方面的编程会有帮助吗?

为了实现这一切,所有不同的线程应该在单个对象上工作?

+2

您可以从线程访问范围内的任何变量。例如2个线程可以调用相同的函数并访问成员实例/静态变量。共享是微不足道的,同步跨多个线程的变量访问是比较困难的任务。 – Gishu 2009-09-01 04:41:06

+1

我们试图将一个线程中的可用对象实例读入另一个线程,并且我们有一个限制来维护全局/静态变量,是否有一个好主意实现它? – 2009-09-01 04:54:47

+0

您不会像这样访问线程。而是访问线程可以看到的对象。如果一个线程中运行的代码可以访问一个对象实例,或者静态数据可以改变它。如果另一个线程可以看到该实例或静态数据,那么您已经在两个线程之间进行通信。 – djna 2009-09-01 05:00:39

回答

5

您可以将对象作为参数传递给Thread.Start,并将其用作当前线程与启动线程之间的共享数据存储。

如果您使用ThreadStart代表的实例表单启动线程,您也可以直接访问(通过适当的课程锁定)数据成员。

您不能使用属性在线程之间创建共享数据。您可以使用附加到您的类的属性实例作为数据存储,但我没有看到如何比使用静态或实例数据成员更好。

+2

要再次用作共享数据存储,还需要进行一些静态/全局变量吗? – 2009-09-01 04:59:18

+0

启动线程的代码显然具有对作为参数传递给Thread.Start的对象的引用。线程过程也具有对该对象的引用。因此,如果没有那个对象必须是一个静态变量,代码段可以写入它。 – 2009-09-01 05:06:56

+2

是的..我明白了..你会写一些代码片段,以便更好地理解 – 2009-09-15 05:34:07

16

你无法打败锁定消息队列的简单性。我说不要把时间浪费在更复杂的事情上。

请阅读声明。

lock

编辑

这里是包裹微软队列对象的例子所以针对它的所有操作都是线程安全的。

public class Queue<T> 
{ 
    /// <summary>Used as a lock target to ensure thread safety.</summary> 
    private readonly Locker _Locker = new Locker(); 

    private readonly System.Collections.Generic.Queue<T> _Queue = new System.Collections.Generic.Queue<T>(); 

    /// <summary></summary> 
    public void Enqueue(T item) 
    { 
     lock (_Locker) 
     { 
      _Queue.Enqueue(item); 
     } 
    } 

    /// <summary>Enqueues a collection of items into this queue.</summary> 
    public virtual void EnqueueRange(IEnumerable<T> items) 
    { 
     lock (_Locker) 
     { 
      if (items == null) 
      { 
       return; 
      } 

      foreach (T item in items) 
      { 
       _Queue.Enqueue(item); 
      } 
     } 
    } 

    /// <summary></summary> 
    public T Dequeue() 
    { 
     lock (_Locker) 
     { 
      return _Queue.Dequeue(); 
     } 
    } 

    /// <summary></summary> 
    public void Clear() 
    { 
     lock (_Locker) 
     { 
      _Queue.Clear(); 
     } 
    } 

    /// <summary></summary> 
    public Int32 Count 
    { 
     get 
     { 
      lock (_Locker) 
      { 
       return _Queue.Count; 
      } 
     } 
    } 

    /// <summary></summary> 
    public Boolean TryDequeue(out T item) 
    { 
     lock (_Locker) 
     { 
      if (_Queue.Count > 0) 
      { 
       item = _Queue.Dequeue(); 
       return true; 
      } 
      else 
      { 
       item = default(T); 
       return false; 
      } 
     } 
    } 
} 

EDIT 2

我希望这个例子可以帮助。请记住,这是光秃秃的骨头。 使用这些基本思想,您可以安全地利用线程的力量。

public class WorkState 
{ 
    private readonly Object _Lock = new Object(); 
    private Int32 _State; 

    public Int32 GetState() 
    { 
     lock (_Lock) 
     { 
      return _State; 
     } 
    } 

    public void UpdateState() 
    { 
     lock (_Lock) 
     { 
      _State++; 
     } 
    } 
} 

public class Worker 
{ 
    private readonly WorkState _State; 
    private readonly Thread _Thread; 
    private volatile Boolean _KeepWorking; 

    public Worker(WorkState state) 
    { 
     _State = state; 
     _Thread = new Thread(DoWork); 
     _KeepWorking = true;     
    } 

    public void DoWork() 
    { 
     while (_KeepWorking) 
     { 
      _State.UpdateState();     
     } 
    } 

    public void StartWorking() 
    { 
     _Thread.Start(); 
    } 

    public void StopWorking() 
    { 
     _KeepWorking = false; 
    } 
} 



private void Execute() 
{ 
    WorkState state = new WorkState(); 
    Worker worker = new Worker(state); 

    worker.StartWorking(); 

    while (true) 
    { 
     if (state.GetState() > 100) 
     { 
      worker.StopWorking(); 
      break; 
     } 
    }     
} 
+0

这不是一个消息队列适合任何目的... – Thorarin 2009-09-01 04:44:46

+0

甚至不传递消息? – ChaosPandion 2009-09-01 04:46:18

+1

我们试图将一个线程中可用的对象实例读入另一个线程,并且我们有一个限制来维护全局/静态变量,是否有一个好主意实现它? – 2009-09-01 04:55:36

3

当你启动一个线程时,你正在执行一些选定类的方法。该类的所有属性都是可见的。

Worker myWorker = new Worker(/* arguments */); 

    Thread myThread = new Thread(new ThreadStart(myWorker.doWork)); 

    myThread.Start(); 

你的线程现在处于的doWork()方法,并且可以看到myWorker的任何atrributes,其本身可以是其他对象。现在你只需要小心处理几个线程同时触发这些属性的情况。

+0

yep ..你的想法是非常有用的,让我详细说明我的情况在这里作为 我们正在尝试读取一个线程中的可用对象实例到另一个线程,并且我们有一个限制来维护全局/静态变量,有没有一些好主意去实现它? – 2009-09-01 04:57:59

+0

你没有详细说明你只是重复你的原始问题。 – ChaosPandion 2009-09-01 04:59:54

+0

请阅读我对你的问题的评论。我想进一步解释,但我需要你的帮助。 – djna 2009-09-01 05:04:32

7

请看下面的例子的代码:

public class MyWorker 
{ 
    public SharedData state; 
    public void DoWork(SharedData someData) 
    { 
     this.state = someData; 
     while (true) ; 
    } 

} 

public class SharedData { 
    X myX; 
    public getX() { etc 
    public setX(anX) { etc 

} 

public class Program 
{ 
    public static void Main() 
    { 
     SharedData data = new SharedDate() 
     MyWorker work1 = new MyWorker(data); 
     MyWorker work2 = new MyWorker(data); 
     Thread thread = new Thread(new ThreadStart(work1.DoWork)); 
     thread.Start(); 
     Thread thread2 = new Thread(new ThreadStart(work2.DoWork)); 
     thread2.Start(); 
    } 
} 

在这种情况下,线程类MyWorker具有可变state。我们初始化它与相同的对象。现在您可以看到两名工作人员访问相同的 SharedData对象。一名工作人员所做的更改对另一名工作人员可见。

您还有其他几个问题。当员工1做出更改时,员工2如何知道?反之亦然?你如何防止冲突的变化?也许阅读:this tutorial

+1

Yap..its附近但不是确切..这里有两个线程但同一个myworker类的实例,对于我来说MyWorker类的两个实例(work1和work2)在不同的线程中,并希望从thread1中的work1读取数据..我们可以做到吗? – 2009-09-01 05:25:49

+0

在这种情况下,您需要将work1对象传递给thread2。您可以使用ParameterizedThreadStart而不是ThreadStart来完成此操作。 – Aamir 2009-09-01 05:31:27

+0

@Amir希望你不介意,我调整了示例以匹配Jaswant的描述 – djna 2009-09-01 06:01:33