30

How to share data between different threads In C# without using the static variables? Can we create a such machanism using attribute?

Will Aspect oriented programming help in such cases?

To acheive this all the different threads should work on single object?

Jaswant Agarwal
  • 4,755
  • 9
  • 39
  • 49
  • 2
    You can access any variable in scope from a thread. e.g. 2 threads can call the same function and access member instance/static variables. Sharing is trivial, synchronizing variable access across multiple threads is the more diff task. – Gishu Sep 01 '09 at 04:41
  • 1
    We are trying to read the available object instance in one thread into another thread, and we have a restriction to maintain global/static variable, is there some good idea to acheive it? – Jaswant Agarwal Sep 01 '09 at 04:54
  • You don't access threads as such. Rather you access objects that threads can see. If code running in one thread can access an object instance, or static data it can change it. If another thread can see that instance or static data then you have communicated between the two threads. – djna Sep 01 '09 at 05:00
  • I suspect that we're all not quite answering your question. How about you post some snippets of your code. Show us how far you have got. I think that the answer is actually much simpler than you fear, but it would be much easier to explain in the context of your own application. – djna Sep 01 '09 at 05:02

4 Answers4

26

You can't beat the simplicity of a locked message queue. I say don't waste your time with anything more complex.

Read up on the lock statement.

lock

EDIT

Here is an example of the Microsoft Queue object wrapped so all actions against it are thread safe.

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

I hope this example helps. Remember this is bare bones. Using these basic ideas you can safely harness the power of threads.

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;
        }
    }                   
}
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
  • 1
    We are trying to read the available object instance in one thread into another thread, and we have a restriction to maintain global/static variable, is there some good idea to acheive it? – Jaswant Agarwal Sep 01 '09 at 04:55
  • Why put a lock in GetState()? Shouldn't you only need a lock around UpdateState()? – goku_da_master Feb 09 '12 at 16:13
  • 2
    @goku_da_master To make sure that your reading will not be corrupted by a thread locking the data while you are reading and changing it before you have finished reading them. – ThunderGr Nov 22 '12 at 10:09
  • +1 .. yes lock() is proppably the easiest and one of the most effective ways – Vengarioth May 11 '13 at 13:58
  • Declaring _KeepWorking `volatile` does not make it thread-safe. In the case where it is a simple type `bool` it might be thread-safe on some processors, but the volatile keyword only guarantees that the compiler won't reorder the instructions. If _KeepWorking happened to be something larger (that is not a register-sized object), it could be corrupted with 2 threads writing to it at the same time. Probably best to wrap it in a lock() { } – Mark Lakata Jun 20 '13 at 01:42
  • @goku_da_master @ThunderGr In this example you dont need the lock at all. In UpdateState it can be replaced with `Interlocked.Increment`. In GetState it can be thrown away because... `Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types.` //C# spec (Because C# like Java is JIT-compiled it is not the responsibility of the application programmer to dabble in processor specifics - it is the JIT'er that has to facilitate these guarantees for whatever hardware it was made for.) – AnorZaken Jan 28 '15 at 16:50
9

You can pass an object as argument to the Thread.Start and use it as a shared data storage between the current thread and the initiating thread.

You can also just directly access (with the appropriate locking of course) your data members, if you started the thread using the instance form of the ThreadStart delegate.

You can't use attributes to create shared data between threads. You can use the attribute instances attached to your class as a data storage, but I fail to see how that is better than using static or instance data members.

Franci Penov
  • 74,861
  • 18
  • 132
  • 169
  • 2
    To use as a shared data storage again need to go for some Static/Global variable? – Jaswant Agarwal Sep 01 '09 at 04:59
  • The code that started the thread obviously has a reference to the object passed as a parameter to the Thread.Start. The thread procedure also has a reference to that object. Thus, but pieces of code can write to it without that object having to be a static variable. – Franci Penov Sep 01 '09 at 05:06
  • 3
    yes.. i got it..will you please write some code snippet for better understanding – Jaswant Agarwal Sep 15 '09 at 05:34
9

Look at the following example code:

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();
    }
}

In this case, the thread class MyWorker has a variable state. We initialise it with the same object. Now you can see that the two workers access the same SharedData object. Changes made by one worker are visible to the other.

You have quite a few remaining issues. How does worker 2 know when changes have been made by worker 1 and vice-versa? How do you prevent conflicting changes? Maybe read: this tutorial.

djna
  • 54,992
  • 14
  • 74
  • 117
Aamir
  • 14,882
  • 6
  • 45
  • 69
  • 1
    Yap..its near by but not exact ..here two threads bbut same instance of myworker class,for me two instance of MyWorker class (work1 and work2) in different threads and want to read data from work1 in thread2..how can we do it? – Jaswant Agarwal Sep 01 '09 at 05:25
  • In that case, you will need to pass the work1 object to the thread2. You can do this by using ParameterizedThreadStart instead of ThreadStart. – Aamir Sep 01 '09 at 05:31
  • @Amir hope you don't mind, I adjusted the example to match Jaswant's description – djna Sep 01 '09 at 06:01
  • @djna: No problem. This is exactly the true purpose of a community-based site. I initially gave him a very trivial example to get him started. – Aamir Sep 01 '09 at 06:11
  • Thanks aamir..it was wht i want:) – Jaswant Agarwal Sep 01 '09 at 06:15
  • This example lacks locking of data. – Farjad Aug 21 '14 at 13:10
3

When you start a thread you are executing a method of some chosen class. All attributes of that class are visible.

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

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

  myThread.Start();

Your thread is now in the doWork() method and can see any atrributes of myWorker, which may themselves be other objects. Now you just need to be careful to deal with the cases of having several threads all hitting those attributes at the same time.

djna
  • 54,992
  • 14
  • 74
  • 117
  • yep..Your Idea is very much usefull, let me elaborate my situation here as We are trying to read the available object instance in one thread into another thread, and we have a restriction to maintain global/static variable, is there some good idea to acheive it? – Jaswant Agarwal Sep 01 '09 at 04:57
  • You did not elaborate you simply repeated your original question. – ChaosPandion Sep 01 '09 at 04:59
  • Please read my comment on your question. I want to explain further but I need you help. – djna Sep 01 '09 at 05:04
  • 1
    okk.. Suppose one instance of a class in one thread, and another thread want to read the data available in that class instance variable, can it be done by applying some attribute on the varible? – Jaswant Agarwal Sep 01 '09 at 05:15
  • Please do this: edit your question, add code snippet to show the relevent classes. You need only a very few lines. We can then show you how to do this. It's **much** easier than you seem to think. So much easier to explain with reference to some cide. – djna Sep 01 '09 at 05:18