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....
Related
When run conflict between class variables!
private myClass[] arrayms = new myClass[5];
foreach (myClass ms in arrayms) {
if (ms.ScheduleState)
Task.Factory.StartNew(() => ms.Start());
}
How can I run Several from a function at the same time from one class? C#
When run _StartTask() conflict between myClass variables and log result messy
private myClass[] arrayms = new myClass[5];
public void _TasksClassCreator()
{
foreach (var ms in arrayms )
{
ms.ScheduleName = SName;
.
.
.
}
}
public void _StartTask()
{
foreach (myClass ms in arrayms)
{
if (ms.ScheduleState)
Task.Factory.StartNew(() => ms.Start());
}
}
public sealed class myClass
{
public void Start()
{
_TBTask();
}
private void _TBTask()
{
while(true)
{
...//Conflict here
// this function always running and reporting result...
//log here
}
}
private string _ScheduleName;
public string ScheduleName
{
get
{
return _ScheduleName;
}
set
{
_ScheduleName = value;
}
.
.
.
}
}
I got a text summary, Classes are object. program do not have error, but only conflict variables when run. –
I don't understand "conflict variables". But the rest seems to fit what I described in my previous comment. i.e. the array is empty when calling foreach. So maybe this:
for (int i=0; i < ms.Length; i++) {
arrayms[i] = new MyClass();
}
// ScheduleState must somehow get set, then:
foreach (myClass ms in arrayms) {
if (ms.ScheduleState)
Task.Factory.StartNew(() => ms.Start());
}
edit
what does Task.Factory.StartNew(..) do? Its name StartNew implies that a new object is created and started. But an anonymous method that starts an existing object is passed. So are we actually starting two things here?
if this (comment, below) is not the problem then maybe it's the infamous scope problem when calling LINQ in a loop:
foreach (myClass ms in arrayms) {
MyClass workAround = ms; // must set "ms" to a loop-scoped variable.
// why? the answer is TL;DR
if (workAround.ScheduleState)
Task.Factory.StartNew(() => workAround.Start());
end edit
This is my first time, so... be gentle ;) Welcome community!
Here's my problem. I have to create multiple objects inside a loop. But I don't know how to do it. Already tried doing it this way:
List<myClass> ObjectList = new List<MyClass>();
and then :
ObjectList.Add(new MyClass(a,b));
Class is with descriptor and params "a" and "b" are set.
So, I'm looking for this :
class myClass
{
int a;
int b;
public MyClass(int A, int B)
{
a=A;
b=B;
}
class Main()
{
Random r=new Random();
MyClass a1 = new MyClass(r.Next(0,11));
MyClass a2 = new MyClass(r.Next(0,11));
MyClass a3 = new MyClass(r.Next(0,11));
MyClass a4 = new MyClass(r.Next(0,11));
MyClass a5 = new MyClass(r.Next(0,11));
MyClass a6 = new MyClass(r.Next(0,11));
}
}
And I have to find a way to create these objects in the loop, cause I cannot know how many of these will be, as I'm reading a matrix from a file.
There is a common solution to the situation where you want to initialise something by repeatedly attempting to acquire an item from a source until the source runs out.
This is called a "loop-and-a-half" construct (and it's a proper "structured" construct, since it is a loop with a single exit).
The general approach goes like this:
while (true)
{
attempt to obtain next item;
if (no more items available)
break loop;
add item to collection;
}
A general implementation in C# might look like this:
class MyClass
{
}
class MyInitData
{
}
static class Program
{
static void Main(string[] args)
{
var list = new List<MyClass>();
while (true)
{
var initData = GetNextItem(); // Returns null when no more items are available.
if (initData == null) // No more items available.
break;
list.Add(CreateMyClassFromInitData(initData));
}
}
static MyInitData GetNextItem() // Returns null when no more items are available.
{
// Code to return next item. Implementation omitted here.
return null;
}
static MyClass CreateMyClassFromInitData(MyInitData initData)
{
// Create a new MyClass from initData. Implementation omitted here.
return new MyClass();
}
}
As another - simpler - example, here's how you might go about reading number strings from a text file and converting them into a list of ints, using a loop-and-a-half:
var list = new List<int>();
using (var reader = File.OpenText("MyFileName.txt"))
{
while (true)
{
string line = reader.ReadLine();
if (line == null)
break;
list.Add(int.Parse(line));
}
}
In my web application i am having following common objectList for all online users.
public static List<MyClass> myObjectList = new List<MyClass>();
so when multiple online users try to read data from this object myObjectList then are there any chances of thread synchronization issue.
In another scenario multiple users are reading from myObjectList and few of them are writing also but every user is writing on a different index of List . Every user may add a new item to this list . So now I think there are chances of synchronization issue.
How to write thread safe utility class that can read and write data from this object in safer way.
Suggestions are highly welcome
Code suggested by Angelo looks like this
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace ObjectPoolExample
{
public class ObjectPool<T>
{
private ConcurrentBag<T> _objects;
private Func<T> _objectGenerator;
public ObjectPool(Func<T> objectGenerator)
{
if (objectGenerator == null) throw new ArgumentNullException("objectGenerator");
_objects = new ConcurrentBag<T>();
_objectGenerator = objectGenerator;
}
public T GetObject()
{
T item;
if (_objects.TryTake(out item)) return item;
return _objectGenerator();
}
public void PutObject(T item)
{
_objects.Add(item);
}
}
class Program
{
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
// Create an opportunity for the user to cancel.
Task.Factory.StartNew(() =>
{
if (Console.ReadKey().KeyChar == 'c' || Console.ReadKey().KeyChar == 'C')
cts.Cancel();
});
ObjectPool<MyClass> pool = new ObjectPool<MyClass> (() => new MyClass());
// Create a high demand for MyClass objects.
Parallel.For(0, 1000000, (i, loopState) =>
{
MyClass mc = pool.GetObject();
Console.CursorLeft = 0;
// This is the bottleneck in our application. All threads in this loop
// must serialize their access to the static Console class.
Console.WriteLine("{0:####.####}", mc.GetValue(i));
pool.PutObject(mc);
if (cts.Token.IsCancellationRequested)
loopState.Stop();
});
Console.WriteLine("Press the Enter key to exit.");
Console.ReadLine();
}
}
// A toy class that requires some resources to create.
// You can experiment here to measure the performance of the
// object pool vs. ordinary instantiation.
class MyClass
{
public int[] Nums {get; set;}
public double GetValue(long i)
{
return Math.Sqrt(Nums[i]);
}
public MyClass()
{
Nums = new int[1000000];
Random rand = new Random();
for (int i = 0; i < Nums.Length; i++)
Nums[i] = rand.Next();
}
}
}
I think i can go with this approach.
If you are using .NET 4.0 you are better off changing to one of the thread-safe collections already supported by the runtime, like for example a ConcurrentBag.
The concurrent bag however does not support access by index if I recall correctly so you may need to resort to a ConcurrentDictionary if you need access to an object by a given key.
If .NET 4.0 is not an option you should read the following blog post:
Why are thread safe collections so hard?
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);
}
}
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);
}