Как обмениваться данными между различными потоками В С# с использованием AOP?
Как обмениваться данными между разными потоками В С# без использования статических переменных?
Можем ли мы создать такой маханизм с использованием атрибута?
Будет ли поддержка ориентированного программирования Aspect в таких случаях?
Чтобы добиться этого, все разные потоки должны работать на одном объекте?
Ответы
Ответ 1
Вы можете передать объект в качестве аргумента Thread.Start
и использовать его в качестве общего хранилища данных между текущим потоком и инициирующим потоком.
Вы также можете напрямую получить доступ (с соответствующей блокировкой) ваших членов данных, если вы начали поток, используя форму экземпляра ThreadStart
.
Вы не можете использовать атрибуты для создания общих данных между потоками. Вы можете использовать экземпляры атрибутов, прикрепленные к вашему классу, как хранилище данных, но я не вижу, как это лучше, чем использование статических или экземпляров данных.
Ответ 2
Вы не можете победить простоту заблокированной очереди сообщений. Я говорю, не тратьте время на что-то более сложное.
Прочитайте инструкцию lock.
lock
ИЗМЕНИТЬ
Вот пример объекта Microsoft Queue, завернутый таким образом, чтобы все действия против него были потокобезопасными.
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;
}
}
}
}
РЕДАКТИРОВАТЬ 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;
}
}
}
Ответ 3
Посмотрите на следующий пример кода:
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. Изменения, сделанные одним работником, видны другим.
У вас довольно много оставшихся проблем. Как рабочий 2 знает , когда изменения были сделаны рабочим 1 и наоборот? Как вы предотвращаете конфликтующие изменения? Возможно, читайте: этот учебник.
Ответ 4
При запуске потока вы выполняете метод некоторого выбранного класса. Все атрибуты этого класса видны.
Worker myWorker = new Worker( /* arguments */ );
Thread myThread = new Thread(new ThreadStart(myWorker.doWork));
myThread.Start();
Ваш поток теперь находится в методе doWork() и может видеть любые атрибуты myWorker, которые сами могут быть другими объектами. Теперь вам просто нужно быть осторожным, чтобы иметь дело с случаями одновременного нажатия нескольких потоков на эти атрибуты.