Is it possible to instantiate a class in a separate thread without a compile time warning?
For example the below code gives the compile time error "Use of unassigned local variable BECheck". I would rather keep AvailabilityCheckBase abstract and not assign it some dummy variable. Creating both BTCheck and BECheck is slow which is why I need it threaded.
public static AvailabilityCheckBase ByDSL(string dsl)
{
AvailabilityCheckBase BECheck;
AvailabilityCheckBase BTCheck;
Thread BEThread = new Thread(new ThreadStart(() => BECheck = new BEAvailabilityCheck(dsl)));
Thread BTThread = new Thread(new ThreadStart(() => BTCheck = new BTAvailabilityCheck(dsl)));
BEThread.Join();
BTThread.Join();
return BECheck.Merge(BTCheck);
}
The language has no knowledge of the Thread constructor or the Join method: it can't tell that you will definitely assign values to both variables before Join returns. If you want to keep the current approach, you'll need to assign values to the variables first. I agree this is slightly ugly, but it's the only way of keeping the compiler happy here.
(It's not clear why you're creating two new threads here, given that your original thread is then blocking on both of them, by the way.)
A better approach if you're using .NET 4 would be to use Task<T>, which effectively gives you the "promise" of a value:
Task<AvailabilityCheckBase> beCheck =
Task.Factory.StartNew(() => new BEAvailabilityCheck(dsl));
Task<AvailabilityCheckBase> btCheck =
Task.Factory.StartNew(() => new BTAvailabilityCheck(dsl));
return beCheck.Result.Merge(btCheck.Result);
It's worth becoming familiar with Task<T> and the TPL in general, as the new async features in C# 5 are heavily dependent on them.
Doesn't this fix your compile error? :
change
AvailabilityCheckBase BECheck;
AvailabilityCheckBase BTCheck;
to
AvailabilityCheckBase BECheck = null;
AvailabilityCheckBase BTCheck = null;
In order to call BECheck.Merge in your last line, BECheck should be initialized, and the compiler doesn't know it will be created before Thread.Join.
Try writing
AvailabilityCheckBase BECheck = null;
AvailabilityCheckBase BTCheck = null;
in the first lines.
If you assign the values to null you should see the message disappear, this would be good practice. There also doesn't appear to be any checking to make sure that the initialisations worked, you should probably include a check for BECheck and BTCheck still being null at the end of the function before you try to return to avoid an exception being thrown.
Use Task's:
Task<AvailabilityCheckBase> BETask = new Task<AvailabilityCheckBase>(() => BECheck = new BEAvailabilityCheck(dsl));
Task<AvailabilityCheckBase> BTTask = new Task<AvailabilityCheckBase>(() => BECheck = new BTAvailabilityCheck(dsl));
BETask.WaitAll(BETask,BTTask);
AvailabilityCheckBase BECheck = BETask.Result;
AvailabilityCheckBase BTCheck = BTTask.Result;
Related
I have a method which takes an argument and run it against database, retrieve records, process and save processed records to a new table. Running the method from the service with one parameter works. What i am trying to achieve now is make the parameter dynamic. I have implemented a method to retrieve the parameters and it works fine. Now i am trying to run methods parallel from the list of parameter's provided. My current implementation is:
WorkerClass WorkerClass = new WorkerClass();
var ParametersList = WorkerClass.GetParams();
foreach (var item in ParametersList){
WorkerClass WorkerClass2 = new WorkerClass();
Parallel.Invoke(
()=>WorkerClass2.ProcessAndSaveMethod(item)
);
}
On the above implementation i think defining a new WorkerClass2 defies the whole point of Parallel.Invoke but i am having an issue with data mixup when using already defined WorkerClass. The reason for the mix up is Oracle connection is opened inside the Init() Method of the class and static DataTable DataCollectionList; is defined on a class level thus creating an issue.
Inside the method ProcessAndSaveMethod(item) i have:
OracleCommand Command = new OracleCommand(Query, OracleConnection);
OracleDataAdapter Adapter = new OracleDataAdapter(Command);
Adapter.Fill(DataCollectionList);
Inside init():
try
{
OracleConnection = new OracleConnection(Passengers.OracleConString);
DataCollectionList = new DataTable();
OracleConnection.Open();
return true;
}
catch (Exception ex)
{
OracleConnection.Close();
DataCollectionList.Clear();
return false;
}
And the function isn't run parallely as i was trying to do. Is there another way to implement this?
To run it in parallel you need to call Parallel.Invoke only once with all the tasks to be completed:
Parallel.Invoke(
ParametersList.Select(item =>
new Action(()=>WorkerClass2.ProcessAndSaveMethod(item))
).ToArray()
);
If you have a list of somethings and want it processed in parallel, there really is no easier way than PLinq:
var parametersList = SomeObject.SomeFunction();
var resultList = parametersList.AsParallel()
.Select(item => new WorkerClass().ProcessAndSaveMethod(item))
.ToList();
The fact that you build up a new connection and use a lot of variables local to the one item you process is fine. It's actually the preferred way to do multi-threading: keep as much local to the thread as you can.
That said, you have to measure if multi-threading is actually the fastest way to solve your problem. Maybe you can do your processing sequentially and then do all your database stuff in one go with bulk inserts, temporary tables or whatever is suited to your specific problem. Splitting a task into smaller tasks for more processors to run is not always faster. It's a tool and you need to find out if that tool is helping in your specific situation.
I achieved parallel processing using the below code and also avoided null pointer exception from DbCon.open() caused by connection pooling using the max degree of parallelism parameter.
Parallel.ForEach(ParametersList , new ParallelOptions() { MaxDegreeOfParallelism = 5 }, item=>
{
WorkerClass Worker= new WorkerClass();
Worker.ProcessAndSaveMethod(item);
});
In the following example, _instance is always resolving to null. How should I be getting the value safely out of the thread?
class GenericThreadManager<TMyClass> where TMyClass : new()
{
private TMyClass _instance;
private object synLock = new object();
private Thread generalThread;
public GenericThreadManager()
{
//wrapped code
lock (this.synLock)
{
generalThread = new Thread(_instance => this._instance = new TMyClass());
generalThread.Start(); // instantiates the object
while (this._instance == null) // allways compares to null even after
// thread completes
{
Thread.Sleep(100);
}
Thread.Sleep(100);
}
//wrapped code
}
Edits based on comments (thank you for the comments)
The while loop after the thread is just to debug / test if the thread is ever completing.
The context – is that this class instantiates an object that takes a long time to build (i.e. loading lots of data) on a thread. This class then governs access to the object until the instantiation is complete. Crudely I was doing this by checking if the object was null.
Although there might be better ways to solve the problem – I would like to understand where I’ve gone wrong in my understanding of threaded code / and Lambda’s.
Crudely – I understood generalThread = new Thread(_instance => this._instance = new TMyClass()); to be setting the threadstart to the Lambda expression:
_instance => this._instance = new TMyClass()
I understand this expression creates a new instance of TMyClass() and place reference to that object in _instance.
I then understood that the threads my not be synchronised, so the value of _instance wouldn’t be reliably set – unless it was set to volatile.
With it set to volatile I get the following compile error:
Error CS0677 'GenericThreadManager<TMyClass>._instance': a volatile field cannot be of the type 'TMyClass'
How do I resolve the above error or synchronise the threads to move the reference to the object to _instance.
# Panagiotis Kanavos could you explain why the each constructor would see a different lock. The GenericThreadManager is making a private instance of TMyClass, a different object, in the GenericThreadManager constructor. It locking on synLock, so in theory, any other methods on GenericThreadManager should block on the lock (this.synLock) if I understand correctly?
I have problems with Windows 8 UI application. I'm using client-server communication and client needs to check new messages all time. So I use such code, where _socket is a StreamSoket:
private async static void MessageReceiver()
{
var dataReader = new DataReader(_socket.InputStream);
dataReader.InputStreamOptions = InputStreamOptions.Partial;
var stringHeader = await dataReader.LoadAsync(4);
if (stringHeader != 0)
{
var bytes = new byte[4];
dataReader.ReadBytes(bytes);
var length = BitConverter.ToInt32(bytes, 0);
var count = await dataReader.LoadAsync((uint) length);
var result = dataReader.ReadString(count);
ParseRequest(result);
}
dataReader.DetachStream();
MessageReceiver();
}
But in the second LoadAsync, when I try to read the string, I have ObjectDisposedException. Can you help me with it? I have no idea, why such exception is thrown.
I've also tried to use DataReader.InputStream.ReadAsync(), but I also had such problem.
I know this is an old post but since I was having the same problem and figured it out I thought I would post the solution for anyone else that stumbles across this. Although I won't claim to know exactly what the cause of this problem is, since I'm primarily a C++ guy, the solution was fairly simple.
The way I fixed it was by declaring the DataReader as a class member, thereby extending it's scope
_socket= new StreamSocket();
_socket.Control.KeepAlive = true;
_socket.Control.NoDelay = true;
_socketReader = new DataReader(_socket.InputStream);
_socketReader.InputStreamOptions = InputStreamOptions.Partial;
My possibly incorrect understanding of the await keyword is that the call is basically put on a new thread and that the rest of the function will continue off on the previous thread. Since the DataReader was declared locally, it will go out of scope once the function completes, leaving the await thread to work off of a disposed object.
If anybody wants to clarify this it would be appreciated.
Based of Alex Sorokoletov's last comment, my guess would be that the one of your important objects (probably the stream) would be disposed in the call to datareader.DetachStream();
Have had a bit of a search, but couldn't find the same situation I'm facing here.
Here's the snippet I'm worried about:
var threadsafeVacantStats = new Dictionary<Thread, StatsNode>();
var threadSafeVacantLocker = new Object();
var threadsafeZoneStats = new Dictionary<Thread, StatsNode>();
var threadSafeZoneLocker = new Object();
Parallel.ForEach(m_TeamAreasByZone[zone.ContainerID], team =>
{
var tempVacantStatNode = CreateASyncStatsNodes(threadSafeVacantLocker, threadsafeVacantStats);
var tempZoneStatNode = CreateASyncStatsNodes(threadSafeZoneLocker, threadsafeZoneStats);
//...other stuff
}
Here's the function it's calling:
private static StatsNode CreateASyncStatsNodes(object threadSafeLocker, Dictionary<Thread, StatsNode> threadsafeTeamStats)
{
StatsNode tempStatsNode;
var currentThread = Thread.CurrentThread;
lock (threadSafeLocker)
{
if (!threadsafeTeamStats.ContainsKey(currentThread))
threadsafeTeamStats[currentThread] = new StatsNode(0, 0);
tempStatsNode = threadsafeTeamStats[currentThread];
}
return tempStatsNode;
}
To me, this looks fine, however resharper is giving a warning for the second call to CreateASyncStatsNodes (the first call is fine).
Following its advice, it turns the block into:
var threadsafeVacantStats = new Dictionary<Thread, StatsNode>();
var threadSafeVacantLocker = new Object();
var threadsafeZoneStats = new Dictionary<Thread, StatsNode>();
var threadSafeZoneLocker = new Object();
object locker = threadSafeZoneLocker;
Dictionary<Thread, StatsNode> stats = threadsafeZoneStats;
Parallel.ForEach(m_TeamAreasByZone[zone.ContainerID], team =>
{
var tempVacantStatNode = CreateASyncStatsNodes(threadSafeVacantLocker, threadsafeVacantStats);
var tempZoneStatNode = CreateASyncStatsNodes(locker, stats);
//...
}
This doesn't really make sense to me, and doesn't seem to actually fix anything (if it was even broken in the first place). Is resharper mistakenly marking giving a warning, or am I missing something?
Resharper doesn't know that Parallel.ForEach execute passed lambda immediately. It suppose that this lambda could be executed later, when closure will be modified and this could produce some problems. You can ignore this warning.
Exactly what warning is ReSharper giving you? Keep in mind static analysis isn't perfect, I would say it's very likely ReSharper is making a mistake. The original code looks fine to me.
Scenario
I have a line of code whereby I pass a good number of parameters into a method.
CODE as described above
foreach(Asset asset in assetList)
{
asset.ContributePrice(m_frontMonthPrice, m_Vol, m_divisor, m_refPrice, m_type,
m_overrideVol, i, m_decimalPlaces, metalUSDFID, metalEURFID);
}
What I really want to do...
What I really want to do is spawn a new thread everytime I call this method so that it does the work quicker (there are a lot of assets).
Envisaged CODE
foreach(Asset asset in assetList)
{
Thread myNewThread =
new Thread(new ThreadStart(asset.ContributePrice (m_frontMonthPrice, m_Vol,
m_divisor, m_refPrice, m_type, m_overrideVol, i, m_decimalPlaces, metalUSDFID,
metalEURFID)));
myNewThread.Start();
}
ISSUES
This is something which has always bothered me......why can't I pass the parameters into the thread.....what difference does it make?
I can't see a way around this that won't involve lots of refactoring......
.......This is an old application, built piece by piece as a result of feature creep.
Therefore, the code itself is messy and hard to read/follow.
I thought I had pinpointed an area to save some time and increase the processing speed but now I've hit a wall with this.
SUGGESTIONS?
Any help or suggestions would be greatly appreciated.
Cheers.
EDIT:
I'm using .Net 3.5.......I could potentially update to .Net 4.0
If you're using C# 3, the easiest way would be:
foreach(Asset asset in assetList)
{
Asset localAsset = asset;
ThreadStart ts = () => localAsset.ContributePrice (m_frontMonthPrice, m_Vol,
m_divisor, m_refPrice, m_type, m_overrideVol, i,
m_decimalPlaces, metalUSDFID, metalEURFID);
new Thread(ts).Start();
}
You need to take a "local" copy of the asset loop variable to avoid weird issues due to captured variables - Eric Lippert has a great blog entry on it.
In C# 2 you could do the same with an anonymous method:
foreach(Asset asset in assetList)
{
Asset localAsset = asset;
ThreadStart ts = delegate { localAsset.ContributePrice(m_frontMonthPrice,
m_Vol, m_divisor, m_refPrice, m_type, m_overrideVol, i,
m_decimalPlaces, metalUSDFID, metalEURFID); };
new Thread(ts).Start();
}
In .NET 4 it would probably be better to use Parallel.ForEach. Even before .NET 4, creating a new thread for each item may well not be a good idea - consider using the thread pool instead.
Spawning a new thread for each task will most likely make the task run significantly slower. Use the thread pool for that as it amortizes the cost of creating new threads. If you're on .NET 4 take a look at the new Task class.
If you need to pass parameters to a thread when starting it, you must use the ParameterizedThreadStart delegate. If you need to pass several parameters, consider encapsulating them in a type.
You could use ParameterizedThreadStart. You'll need to wrap all of your parameters into a single object. (Untested code below).
struct ContributePriceParams
{
public decimal FrontMonthPrice;
public int Vol;
//etc
}
//...
foreach(Asset asset in assetList)
{
ContributePriceParams pStruct = new pStruct() {FrontMonthPrice = m_frontMonthPrice, Vol = m_vol};
ParameterizedThreadStart pStart = new ParameterizedThreadStart(asset.ContributePrice);
Thread newThread = new Thread(pStart);
newThread.Start(pStruct);
}