Threading in c# - c#

How to call a function which takes two parameters using threading in C#?
I have to call StartDNIThread(string storeID, string queryObject) from another function.I have to pass the two values.Both are string

Your options are:
Encapsulate the parameters in a new class, and put the method to use for the delegate into that class.
Use anonymous functions (anonymous methods or lambda expressions) to do the same thing automatically with captured variables.
The latter is generally easier of course. You haven't shown what you're doing with the thread, but you might do something like:
string storeID = "...";
string queryObject = "...";
Thread t = new Thread(() => StartDNIThread(storeID, queryObject));
t.Start();
Note that because the variables are captured, you shouldn't change the values until after you know the thread has actually started. You can work around this by using captured variables only used by the anonymous function:
string storeID = "...";
string queryObject = "...";
string storeIDCopy = storeID;
string queryObjectCopy = queryObject;
Thread t = new Thread(() => StartDNIThread(storeIDCopy, queryObjectCopy));
t.Start();
// You can now change storeID and queryObject freely
This is particularly important if you're doing anything in a loop, as the loop variables themselves will change. For example:
foreach (string storeID in stores)
{
string storeIDCopy = storeID;
Thread t = new Thread(() => StartDNIThread(storeIDCopy, queryObject));
t.Start();
}
If you're using the thread pool or any other way of starting threads, the pattern is basically the same.

ThreadStart threadStart = delegate{StartDNIThread(string storeID, string queryObject);};
Thread thread = new Thread(threadStart);
thread.Start();
Or with lambdas:
ThreadStart threadStart = () => StartDNIThread(string storeID, string queryObject);
Thread thread = new Thread(threadStart);
thread.Start();

Using the threadpool:
string str1 = "str1";
string str2 = "str2";
ThreadPool.QueueUserWorkItem(state =>
{
Console.WriteLine("{0}:{1}", str1, str2);
});
If you want to do some alternate-thread processing involving a UI, you're best using the BackgroundWorker.

There is a ParameterizedThreadStart delegate which you could use.
This delegate requires a method which takes one argument (of tyoe object). So, in fact you could use a custom type (class or struct) which contains the 2 variables that you want to pass to the ParameterizedThreadStart.
Like this:
Thread t = new Thread (new ParameterizedThreadStart (DoWork));
t.Start(new MyType(storeId, queryObject));
But, in such situations, I prefer to do it in another way. I prefer to create a custom 'Task' type, which abstracts all of these things.
Like this:
public class Task
{
private readonly int _storeId;
private readonly string _queryObject;
public Task(int storeId, string queryObject)
{
_storeId = storeId;
_queryObject = queryObject;
}
public void Start()
{
Thread t = new Thread (new ThreadStart(DoWork));
t.Start();
}
private void DoWork()
{
// Do your thing here.
}
}

I tend to create a task object something like the following
class myClass
{
public void CallingCode()
{
ProcessRequest pr1 = new ProcessRequest("storeD","queryObj");
ThreadStart ts1 = new ThreadStart(pr1.Go);
Thread wrk = new Thread(ts1);
wrk.Start();
}
}
class ProcessRequest
{
private string storeD;
private string queryObj;
public ProcessRequest(string storeD, string queryObj)
{
this.stroreD = storeD;
this.queryObj = queryObj;
}
public void Go()
{
try
{//your processing code here you can access $this->storeD and $this->queryObj
}
catch (Exception ex)
{
}
}
}

I personally like the delegate route:
private delegate void StartDNIThreadDelegate(string storeID, string queryObject);
private static void Main()
{
string storeID = "...";
string queryObject = "...";
StartDNIThreadDelegate startDNIThread = new StartDNIThreadDelegate(StartDNIThread);
IAsyncResult result = startDNIThread.BeginInvoke(storeID, queryObject, new AsyncCallback(StartDNIThreadDone), startDNIThread);
// Do non-threaded stuff...
result.AsyncWaitHandle.WaitOne(); // wait for thread to finish.
}
private static void StartDNIThread(string storeID, string queryObject)
{
// Do StartDNIThreading stuff.
}
private static void StartDNIThreadDone(IAsyncResult result)
{
StartDNIThreadDelegate startDNIThread = (StartDNIThreadDelegate)result.AsyncState;
// Do after thread finished cleanup.
startDNIThread.EndInvoke(result);
}

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

working with threads - add to collection

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

Categories