working with threads - add to collection - c#

List<int> data=new List<int>();
foreach(int id in ids){
var myThread=new Thread(new ThreadStart(Work));
myThread.Start(id);
}
Work(){
}
Method Work does some processing on the received id and then adds the result to the data list? How can I add data to the collection from each thread? How would my code look like? thanks

If you're using .NET 4, I strongly suggest you use Parallel Extensions instead. For example:
var list = ids.AsParallel()
.Select(Work)
.ToList();
where Work is:
public int Work(int id)
{
...
}
so that it can receive the id appropriately. If you're not keen on the method conversion, you could add a lambda expression:
var list = ids.AsParallel()
.Select(id => Work(id))
.ToList();
Either way, this will avoid creating more threads than you really need, and deal with the thread safety side of things without you having to manage the locks yourself.

First of all, you need to protect your multithreaded access with a lock. Second, you need to pass the parameter to your thread (or use lambda which can capture the local variable; beware that if you capture loop variable, it will change the value during the loop, so you ought to have a local copy).
object collectionLock = new object();
List<int> data = new List<int>();
foreach (int id in ids)
{
Thread t = new Thread(Worker);
t.Start(id);
}
void Worker(object o)
{
int id = (int)o;
lock(collectionLock)
{
data.Add(id);
}
}

you can pass and retrieve data (using callbacks) from threads. See MSDN article.
Example:
public class SomeClass
{
public static List<int> data = new List<int>();
public static readonly object obj = new object();
public void SomeMethod(int[] ids)
{
foreach (int id in ids)
{
Work w = new Work();
w.Data = id;
w.callback = ResultCallback;
var myThread = new Thread(new ThreadStart(w.DoWork));
myThread.Start();
}
}
public static void ResultCallback(int d)
{
lock (obj)
{
data.Add(d);
}
}
}
public delegate void ExampleCallback(int data);
class Work
{
public int Data { get; set; }
public ExampleCallback callback;
public void DoWork()
{
Console.WriteLine("Instance thread procedure. Data={0}", Data);
if (callback != null)
callback(Data);
}
}

Related

Getting Collection was modified; enumeration operation may not execute. exception

Getting Collection was modified; enumeration operation may not execute. exception
Code:
public static string GetValue(List<StateBag> stateBagList, string name)
{
string retValue = string.Empty;
if (stateBagList != null)
{
foreach (StateBag stateBag in stateBagList)
{
if (stateBag.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
retValue = stateBag.Value;
}
}
}
return retValue;
}
getting this exception some time times not every time at this place.
stacktrace:
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource
resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at Tavisca.TravelNxt.Shared.Entities.StateBag.GetValue(List`1 stateBagList, String name)
#no one i have tried for following code but still getting exception
code:
class StateBag
{
public string Name;
public string Value;
}
class Program
{
static List<StateBag> _concurrent = new List<StateBag>();
static void Main()
{
var sw = new Stopwatch();
try
{
sw.Start();
Thread thread1 = new Thread(new ThreadStart(A));
Thread thread2 = new Thread(new ThreadStart(B));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
sw.Stop();
}
catch (Exception ex)
{
}
Console.WriteLine("Average: {0}", sw.ElapsedTicks);
Console.ReadKey();
}
private static Object thisLock = new Object();
public static string GetValue(List<StateBag> stateBagList, string name)
{
string retValue = string.Empty;
if (stateBagList != null)
{
lock (thisLock)
{
foreach (StateBag stateBag in stateBagList)
{
if (stateBag.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
retValue = stateBag.Value;
}
}
}
}
return retValue;
}
static void A()
{
for (int i = 0; i < 5000; i++)
{
_concurrent.Add(new StateBag() { Name = "name" + i, Value = i.ToString() });
}
}
static void B()
{
for (int i = 0; i < 5000; i++)
{
var t = GetValue(_concurrent, "name" + i);
}
}
}
Getting Collection was modified; enumeration operation may not execute. exception
Reason: This exception occurs when the enumeration that you are looping through is modified in same thread or some other thread.
Now, in the code that you have provided there isnn't any such scenario. Which means that you might be calling this in a multi-threaded environment and collection is modified in some other thread.
Solution: Implement locking on your enumeration so that only one thread gets access at a time. Something like this should do it.
private static Object thisLock = new Object();
public static string GetValue(List<StateBag> stateBagList, string name)
{
string retValue = string.Empty;
if (stateBagList != null)
{
lock(thisLock)
{
foreach (StateBag stateBag in stateBagList)
{
if (stateBag.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
retValue = stateBag.Value;
}
}
}
}
return retValue;
}
Although locking is the right way to go for fixing the original implementation, there might be a better approach altogether which will involve a lot less code and potential bugs.
The following demo console app uses ConcurrentDictionary instead of List, and is fully threadsafe without the need for your own locking logic.
It also offers better performance, as a dictionary lookup is much faster than serially searching a list:
class StateBag
{
public string Name;
public string Value;
}
class Program
{
public static string GetValue(ConcurrentDictionary<string, StateBag> stateBagDict, string name)
{
StateBag match;
return stateBagDict.TryGetValue(name.ToUpperInvariant(), out match) ?
match.Value : string.Empty;
}
static void Main(string[] args)
{
var stateBagDict = new ConcurrentDictionary<string, StateBag>();
var stateBag1 = new StateBag { Name = "Test1", Value = "Value1" };
var stateBag2 = new StateBag { Name = "Test2", Value = "Value2" };
stateBagDict[stateBag1.Name.ToUpperInvariant()] = stateBag1;
stateBagDict[stateBag2.Name.ToUpperInvariant()] = stateBag2;
var result = GetValue(stateBagDict, "test1");
Console.WriteLine(result);
}
}
This is happening because some other thread in your application is modifying the stateBagList. There are 2 thing you can do... either use locking around your code block where you refer the stateBagList or you can make a deep copy of stateBagList in GetValues method and then use the new list in your for loop.
As already suggested you need to place a lock around the enumeration.
However that action is only effective if you also lock around the statements that are modifying the collection.
static void A()
{
for (int i = 0; i < 5000; i++)
{
lock(thisLock)
{
_concurrent.Add(new StateBag() { Name = "name" + i, Value = i.ToString() });
}
}
}
Otherwise all you are doing is ensuring that only one thread can enumerate the collection at a time. A single thread or multiple other threads could still be modifying the collection while this single enumeration takes place.
I'd also recommend the following link:
http://www.albahari.com/threading/part2.aspx#_Thread_Safety_and_NET_Framework_Types
Other tips:
It is possible to lock on the collection itself like so:
lock(_concurrent) { //statements}
And the GetValue method can be simplified like so:
public static string GetValue(List<StateBag> stateBagList, string name)
{
if (stateBagList != null)
{
lock (thisLock)
{
return stateBagList.FirstOrDefault
(x => x.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
}
}
}
return string.Empty;
}
Replace List with SynchronizedCollection. It is thread-safe collection class.
It does this via locking so that you essentially have a List where every access is wrapped in a lock statement.

Send multiple objects between threads using invoke in c#

I'm having problems with passing loaded data from one thread to another to add the data to the form. I added another object into "var obj = new object[] { names }" and got "Parameter count mismatch". I'd still prefer to pass "Clients" and "Messages" from "LoadData()" in the second thread to "UpdateFormMethod()" in the first one, but I have no idea how to do it. I'd be grateful if anyone could help me with this problem.
Here's the important part of the code within one class:
private readonly Thread _thread;
public readonly Loader Loader = new Loader();
public Dictionary<string, Client> Clients;
public Dictionary<string, Message> Messages;
private bool _stopData = false;
public delegate void UpdateForm(object data);
public UpdateForm MyDelegate;
public Fcon() {
InitializeComponent();
MyDelegate = new UpdateForm(UpdateFormMethod);
_thread = new Thread(LoadData);
_thread.Start();
}
public void UpdateFormMethod(object data) {
foreach (var str in ((IEnumerable<string>)data).Where(str => !fcon_container_users_list.Items.Contains(str))) {
fcon_container_users_list.Items.Insert(0, str);
}
}
public void LoadData() {
while (!_stopData) {
Clients = Loader.GetClients(Operator);
Messages = Loader.GetMessages(Operator);
var status = Loader.SetStatus(Operator);
var names = new string[Clients.Count];
var x = 0;
foreach (var kvp in Clients) {
names[x] = "user_" + kvp.Value.id_fcon_client;
x++;
}
var obj = new object[] { names };
this.Invoke(this.MyDelegate, obj);
Thread.Sleep(1000);
}
}
public void StopData() {
_stopData = true;
}
It sounds like you're not entirely clear where the signature is coming from. It's your own delegate - if you want to change the signature, just change the signature of the delegate and the method implementing it:
public delegate void UpdateForm(IEnumerable<string> data, int foo);
...
public void UpdateFormMethod(IEnumerable<string> data, int foo) {
foreach (var str in data.Where(str =>
!fcon_container_users_list.Items.Contains(str))) {
fcon_container_users_list.Items.Insert(0, str);
}
}
Then:
var obj = new object[] { names, someIntVariable };
this.Invoke(this.MyDelegate, obj);
Or more simply:
this.Invoke(this.MyDelegate, names, someIntVariable);
I'd probably use the existing Action<T>, Action<T1, T2> delegates rather than creating new ones though OR T Func<T1 [,T2]> if you require a return type.
you are passing an object [] in but you should only pass in object.
To send it in just cast it as object i.e.
this.Invoke(this.MyDelegate, (object)obj);
and cast it back inside the method. The reason they specified object as the parameter type is that it allows them not to have to specify many many signatures I think

Starting a new thread in a foreach loop

I have a List of objects and I'd like to loop over that list and start a new thread, passing in the current object.
I've written an example of what I thought should do this, but it's not working. Specifically, it seems like the threads are getting overwritten on each iteration. This doesn't really make sense to me though because I'm making a new Thread object each time.
This is the test code I wrote
class Program
{
static void Main(string[] args)
{
TestClass t = new TestClass();
t.ThreadingMethod();
}
}
class TestClass
{
public void ThreadingMethod()
{
var myList = new List<MyClass> { new MyClass("test1"), new MyClass("test2") };
foreach(MyClass myObj in myList)
{
Thread myThread = new Thread(() => this.MyMethod(myObj));
myThread.Start();
}
}
public void MyMethod(MyClass myObj) { Console.WriteLine(myObj.prop1); }
}
class MyClass
{
public string prop1 { get; set; }
public MyClass(string input) { this.prop1 = input; }
}
The output on my machine is
test2
test2
but I expected it to be
test1
test2
I tried changing the thread lines to
ThreadPool.QueueUserWorkItem(x => this.MyMethod(myObj));
but none of the threads started.
I think I just have a misunderstanding about how threads are supposed to work. Can someone point me in the right direction and tell me what I'm doing wrong?
This is because you're closing over a variable in the wrong scope. The solution here is to use a temporary in your foreach loop:
foreach(MyClass myObj in myList)
{
MyClass tmp = myObj; // Make temporary
Thread myThread = new Thread(() => this.MyMethod(tmp));
myThread.Start();
}
For details, I recommend reading Eric Lippert's post on this exact subject: Closing over the loop variable considered harmful
The problem is that you are using the most current value of the object inside of your closure. So, each invocation of the thread is looking at the same value. To get around this, copy the value into a local variable:
foreach(MyClass myObj in myList)
{
MyClass localCopy = myObj;
Thread myThread = new Thread(() => this.MyMethod(localCopy));
myThread.Start();
}
Agree with Reed's answer (+1).
I would add that if you are on .NET 4, you may want to look at the Task Parallel Library to solve this class of problem. Specifically for this case, have a look at Parallel.ForEach().
if sequence is not matter than go for
Parallel.ForEach(myList, obj => this.MyMethod(obj) );
Write a Simple Parallel.ForEach Loop
I prefer this way:
public void ThreadingMethod()
{
var myList = new List<MyClass> { new MyClass("test1"), new MyClass("test2") };
Parallel.ForEach(myList, new ParallelOptions() { MaxDegreeOfParallelism = 100 },
(myObj, i, j) =>
{
MyMethod(myObj);
});
}
not tested though....

Threading Parallel Invoke, Action

My code as below
public void DownloadConcurrent(Action<string> Methord)
{
Action<string>[] methordList = new Action<string>[Concurent_Downloads];
for (int i = 0; i < Concurent_Downloads; i++)
{
methordList[i] = Methord;
}
Parallel.Invoke(methordList);
}
Parallel.Invoke is giving error:
"cannot convert from 'System.Action<string>[]' to 'System.Action[]'"
The Method it is calling is
public void DownloadLinks(string Term)
{
}
check Parallel.ForEach like the following
static void Main(string[] args)
{
List<string> p = new List<string>() { "Test", "Test2", "Test3"};
Parallel.ForEach(p, Test);
}
public static void Test(string test)
{
Debug.WriteLine(test);
}
This should do the trick for you
HTH
Dominik
In your case it is easier if you use
Parallel.ForEach
over your string list instead of using
Parallel.Invoke
with additional parameter. Let me know if you want to stick to Parallel.Invoke.
Parallel.Invoke accepts Action array while your code is passing it an Action<string> array. What you can do is :
public void DownloadConcurrent(Action<string> Methord)
{
Action<string>[] methordList = new Action<string>[Concurent_Downloads];
var r = methordList.Select(a => (Action)(() => a("some_str"))).ToArray();
Parallel.Invoke(r);
}
You need to replace some_str with proper value for each action

Get list of object's from collection being updated by thread

I have a Dictionary of items that a thread is updating. I want to have a method get the updated list of items using another thread.
Like so:
internal List<string> GetListOfEntities()
{
List<string> listOfEntities = new List<string>();
foreach (string entityName in ModelFacade._totalListOfStkObjects.Keys)
{
listOfEntities.Add(entityName);
}
return listOfEntities;
}
ModelFacade._totalListOfStkObjects is the collection being updated by the thread. I keep getting the exception: "Collection was modified; enumeration operation may not execute."; I have tried copying _totalListOfStkObjects to a local collection and iterating over that in GetListOfEntities().. but I get the same error..?
Any help ?
WulfgarPro
There isn't going to be a guaranteed thread-safe way to access the dictionary. Your best bet is to either change your code so that you're not sharing the collection or to to lock the dictionary when accessing:
object dictLock = new object();
internal List<string> GetListOfEntities()
{
lock (dictLock)
{
return ModelFacade._totalListOfStkObjects.Keys.ToList();
}
}
Make sure you also lock the dictionary when modifying it in another thread.
Change your Dictionary to ConcurrentDictionary if you are using .NET 4. Here is an easy example to simulate your question and resolve it.
class DataItem
{
public int Data { get; set; }
public bool IsDirty { get; set; }
}
var data = new ConcurrentDictionary<string, DataItem>();
Thread addingItems = new Thread(() =>
{
for (int i = 0; i < 10000; i++)
{
data.TryAdd("data " + i, new DataItem { Data = i, IsDirty = true });
Thread.Sleep(100);
}
});
Thread fetchingItems = new Thread(() =>
{
int count = 0;
while (count < 100)
{
foreach (var item in data)
{
if (item.Value.IsDirty)
{
Console.WriteLine(item.Key + " " + item.Value);
item.Value.IsDirty = false;
count++;
}
}
}
});
addingItems.Start();
fetchingItems.Start();
You can wrap the dictionary up in a thread-safe singleton class. This should provide all of the functionality of ConcurrentDictionary to Dictionary. Referencing the Dictionary should only require one additional layer of indirection.
Reference:
Singleton.Instance.myDictionary.Add(1, "Hello World");
Declaration:
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
public Dictionary<int, string> myDictionary = new Dictionary<int, string>();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Look here for more information on the Singleton Pattern in C#. Note that there is only one difference between the pattern on this link and my example code.

Categories