I have an event source which fired by a Network I/O very frequently, based on underlying design, of course the event was always on different thread each time, now I wrapped this event via Rx with: Observable.FromEventPattern(...), now I'm using the TakeWhile(predict) to filter some special event data.
At now, I have some concerns on its thread safety, the TakeWhile(predict) works as a hit and mute, but in concurrent situation, can it still be guaranteed? because I guess the underlying implementation could be(I can't read the source code since it's too complicated...):
public static IObservable<TSource> TakeWhile<TSource>(this IObservable<TSource> source, Func<TSource, bool> predict)
{
ISubject<TSource> takeUntilObservable = new TempObservable<TSource>();
IDisposable dps = null;
// 0 for takeUntilObservable still active, 1 for predict failed, diposed and OnCompleted already send.
int state = 0;
dps = source.Subscribe(
(s) =>
{
/* NOTE here the 'hit and mute' still not thread safe, one thread may enter 'else' and under CompareExchange, but meantime another thread may passed the predict(...) and calling OnNext(...)
* so the CompareExchange here mainly for avoid multiple time call OnCompleted() and Dispose();
*/
if (predict(s) && state == 0)
{
takeUntilObservable.OnNext(s);
}
else
{
// !=0 means already disposed and OnCompleted send, avoid multiple times called via parallel threads.
if (0 == Interlocked.CompareExchange(ref state, 1, 0))
{
try
{
takeUntilObservable.OnCompleted();
}
finally
{
dps.Dispose();
}
}
}
},
() =>
{
try
{
takeUntilObservable.OnCompleted();
}
finally { dps.Dispose(); }
},
(ex) => { takeUntilObservable.OnError(ex); });
return takeUntilObservable;
}
That TempObservable is just a simple implementation of ISubject.
If my guess reasonable, then seems the thread safety can't be guaranteed, means some unexpected event data may still incoming to OnNext(...) because that 'mute' is still on going.
Then I write a simple testing to verify, but out of expectation, the results are all positive:
public class MultipleTheadEventSource
{
public event EventHandler OnSthNew;
int cocurrentCount = 1000;
public void Start()
{
for (int i = 0; i < this.cocurrentCount; i++)
{
int j = i;
ThreadPool.QueueUserWorkItem((state) =>
{
var safe = this.OnSthNew;
if (safe != null)
safe(j, null);
});
}
}
}
[TestMethod()]
public void MultipleTheadEventSourceTest()
{
int loopTimes = 10;
int onCompletedCalledTimes = 0;
for (int i = 0; i < loopTimes; i++)
{
MultipleTheadEventSource eventSim = new MultipleTheadEventSource();
var host = Observable.FromEventPattern(eventSim, "OnSthNew");
host.TakeWhile(p => { return int.Parse(p.Sender.ToString()) < 110; }).Subscribe((nxt) =>
{
//try print the unexpected values, BUT I Never saw it happened!!!
if (int.Parse(nxt.Sender.ToString()) >= 110)
{
this.testContextInstance.WriteLine(nxt.Sender.ToString());
}
}, () => { Interlocked.Increment(ref onCompletedCalledTimes); });
eventSim.Start();
}
// simply wait everything done.
Thread.Sleep(60000);
this.testContextInstance.WriteLine("onCompletedCalledTimes: " + onCompletedCalledTimes);
}
before I do the testing, some friends here suggest me try to use Synchronize<TSource> or ObserveOn to make it thread safe, so any idea on my proceeding thoughts and why the issue not reproduced?
As per your other question, the answer still remains the same: In Rx you should assume that Observers are called in a serialized fashion.
To provider a better answer; Originally the Rx team ensured that the Observable sequences were thread safe, however the performance penalty for well behaved/designed applications was unnecessary. So a decision was taken to remove the thread safety to remove the performance cost. To allow you to opt back into to thread safety you could apply the Synchronize() method which would serialize all method calls OnNext/OnError/OnCompleted. This doesn't mean they will get called on the same thread, but you wont get your OnNext method called while another one is being processed.
The bad news, from memory this happened in Rx 2.0, and you are specifically asking about Rx 1.0. (I am not sure Synchonize() even exists in 1.xx?)
So if you are in Rx v1, then you have this blurry certainty of what is thread safe and what isn't. I am pretty sure the Subjects are safe, but I can't be sure about the factory methods like FromEventPattern.
My recommendation is: if you need to ensure thread safety, Serialize your data pipeline. The easiest way to do this is to use a single threaded IScheduler implementation i.e. DispatcherScheduler or a EventLoopScheduler instance.
Some good news is that when I wrote the book on Rx it did target v1, so this section is very relevant for you http://introtorx.com/Content/v1.0.10621.0/15_SchedulingAndThreading.html
So if your query right now looked like this:
Observable.FromEventPatter(....)
.TakeWhile(x=>x>5)
.Subscribe(....);
To ensure that the pipeline is serialized you can create an EventLoopScheduler (at the cost of dedicating a thread to this):
var scheduler = new EventLoopScheduler();
Observable.FromEventPatter(....)
.ObserveOn(scheduler)
.TakeWhile(x=>x>5)
.Subscribe(....);
Related
I have some c# code (MVC WebAPI) which iterates over an array of IDs in parallel and makes an API call for each entry. In the first version, the whole code was a simple, synchronous for loop. Now we changed that to a combination of Task.WhenAll and a LINQ select:
private async Task RunHeavyLoad(IProgress<float> progress) {
List<MyObj> myElements = new List<MyObj>(someEntries);
float totalSteps = 1f / myElements.Count();
int currentStep = 0;
await Task.WhenAll(myElements.Select(async elem => {
var result = await SomeHeavyApiCall(elem);
DoSomethingWithThe(result);
progress.Report(totalSteps * System.Threading.Interlocked.Increment(ref currentStep) * .1f);
}
// Do some more stuff
}
This is a simplified version of the original method! The actual method EnforceImmediateImport is called by this SignalR hub method:
public class ImportStatusHub : Hub {
public async Task RunUnscheduledImportAsync(DateTime? fromDate, DateTime? toDate) {
Clients.Others.enableManualImport(false);
try {
Progress<float> progress = new Progress<float>((p) => Clients.All.updateProgress(p));
await MvcApplication.GlobalScheduler.EnforceImmediateImport(progress, fromDate, toDate);
} catch (Exception ex) {
Clients.All.importError(ex.Message);
}
Clients.Others.enableManualImport(true);
}
}
Now I wonder, if this is "thread safe" per se, or if I need to do something with the progress.Report calls to prevent anything from going wrong.
From the docs:
Remarks
Any handler provided to the constructor or event handlers
registered with the ProgressChanged event are invoked through a
SynchronizationContext instance captured when the instance is
constructed. If there is no current SynchronizationContext at the time
of construction, the callbacks will be invoked on the ThreadPool.
For more information and a code example, see the article Async in 4.5:
Enabling Progress and Cancellation in Async APIs in the .NET Framework
blog.
Like anything else using the SynchronizationContext, it's safe to post from multiple threads.
Custom implementations of IProgress<T> should have their behavior defined.
On your question, internally, Progress only does invoking. It is up to the code you wrote to handle the progress on the other side. I would say that the line progress.Report(totalSteps * System.Threading.Interlocked.Increment(ref currentStep) * .1f); can cause a potential progress reporting issue due to the multiplication which is not atomic.
This is what happens internally inside Progress when you call Report
protected virtual void OnReport(T value)
{
// If there's no handler, don't bother going through the sync context.
// Inside the callback, we'll need to check again, in case
// an event handler is removed between now and then.
Action<T> handler = m_handler;
EventHandler<T> changedEvent = ProgressChanged;
if (handler != null || changedEvent != null)
{
// Post the processing to the sync context.
// (If T is a value type, it will get boxed here.)
m_synchronizationContext.Post(m_invokeHandlers, value);
}
}
On the code though, a better way to run in parallel is to use PLinq. In your current code, if the list contains many items, it will spin up tasks for every single item at the same time and wait for all of them to complete. However, in PLinq, the number of concurrent executions will be determined for you to optimize performance.
myElements.AsParallel().ForAll(async elem =>
{
var result = await SomeHeavyApiCall(elem);
DoSomethingWithThe(result);
progress.Report(totalSteps * System.Threading.Interlocked.Increment(ref currentStep) * .1f);
}
Please keep in mind that AsParallel().ForAll() will immediately return when using async func. So you might want to capture all the tasks and wait for them before you proceed.
One last thing, if your list is being edited while it is being processed, i recommend using ConcurrentQueue or ConcurrentDictionary or ConcurrentBag.
I'm trying to implement a consumer in C#. There are many publishers which could be executing concurrently. I've created three examples, one with Rx and subject, one with BlockingCollection and a third using ToObservable from the BlockingCollection. They all do the same thing in this simple example and I want them to work with multiple producers.
What are the different qualities of each approach?
I'm already using Rx, so I'd prefer this approach. But I'm concerned that OnNext has no thread safe guarantee and I don't know what the queuing semantics are of Subject and the default scheduler.
Is there a thread safe subject?
Are all messages going to be processed?
Are there any other scenarios when this wont work? Is it processing concurrently?
void SubjectOnDefaultScheduler()
{
var observable = new Subject<long>();
observable.
ObserveOn(Scheduler.Default).
Subscribe(i => { DoWork(i); });
observable.OnNext(1);
observable.OnNext(2);
observable.OnNext(3);
}
Not Rx, but easily adapted to use/subscribe it. It takes an item and then processes it. This should happen serially.
void BlockingCollectionAndConsumingTask()
{
var blockingCollection = new BlockingCollection<long>();
var taskFactory = new TaskFactory();
taskFactory.StartNew(() =>
{
foreach (var i in blockingCollection.GetConsumingEnumerable())
{
DoWork(i);
}
});
blockingCollection.Add(1);
blockingCollection.Add(2);
blockingCollection.Add(3);
}
Using a blocking collection a bit like a subject seems like a good compromise. I'm guessing implicitly will schedule onto task, so that I can use async/await, is that correct?
void BlockingCollectionToObservable()
{
var blockingCollection = new BlockingCollection<long>();
blockingCollection.
GetConsumingEnumerable().
ToObservable(Scheduler.Default).
Subscribe(i => { DoWork(i); });
blockingCollection.Add(1);
blockingCollection.Add(2);
blockingCollection.Add(3);
}
Subject is not thread-safe. OnNexts issued concurrently will directly call an Observer concurrently. Personally I find this quite surprising given the extent to which other areas of Rx enforce the correct semantics. I can only assume this was done for performance considerations.
Subject is kind of a half-way house though, in that it does enforce termination with OnError or OnComplete - after either of these are raised, OnNext is a NOP. And this behaviour is thread-safe.
But use Observable.Synchronize() on a Subject and it will force outgoing calls to obey the proper Rx semantics. In particular, OnNext calls will block if made concurrently.
The underlying mechanism is the standard .NET lock. When the lock is contended by multiple threads they are granted the lock on a first-come first-served basis most of the time. There are certain conditions where fairness is violated. However, you will definitely get the serialized access you are looking for.
ObserveOn has behaviour that is platform specific - if available, you can supply a SynchronizationContext and OnNext calls are Posted to it. With a Scheduler, it ends up putting calls onto a ConcurrentQueue<T> and dispatching them serially via the scheduler - so the thread of execution will depend on the scheduler. Either way, the queuing behaviour will also enforce the correct semantics.
In both cases (Synchronize & ObserveOn), you certainly won't lose messages. With ObserveOn, you can implicitly choose thread you'll process messages on by your choice of Scheduler/Context, with Synchronize you'll process messages on the calling thread. Which is better will depend on your scenario.
There's more to consider as well - such as what you want to do if your producers out-pace your consumer.
You might want to have a look at Rxx Consume as well: http://rxx.codeplex.com/SourceControl/changeset/view/63470#1100703
Sample code showing Synchronize behaviour (Nuget Rx-Testing, Nunit) - it's a bit hokey with the Thread.Sleep code but it's quite fiddly to be bad and I was lazy :):
public class SubjectTests
{
[Test]
public void SubjectDoesNotRespectGrammar()
{
var subject = new Subject<int>();
var spy = new ObserverSpy(Scheduler.Default);
var sut = subject.Subscribe(spy);
// Swap the following with the preceding to make this test pass
//var sut = subject.Synchronize().Subscribe(spy);
Task.Factory.StartNew(() => subject.OnNext(1));
Task.Factory.StartNew(() => subject.OnNext(2));
Thread.Sleep(2000);
Assert.IsFalse(spy.ConcurrencyViolation);
}
private class ObserverSpy : IObserver<int>
{
private int _inOnNext;
public ObserverSpy(IScheduler scheduler)
{
_scheduler = scheduler;
}
public bool ConcurrencyViolation = false;
private readonly IScheduler _scheduler;
public void OnNext(int value)
{
var isInOnNext = Interlocked.CompareExchange(ref _inOnNext, 1, 0);
if (isInOnNext == 1)
{
ConcurrencyViolation = true;
return;
}
var wait = new ManualResetEvent(false);
_scheduler.Schedule(TimeSpan.FromSeconds(1), () => wait.Set());
wait.WaitOne();
_inOnNext = 0;
}
public void OnError(Exception error)
{
}
public void OnCompleted()
{
}
}
}
In my quest to build a condition variable class I stumbled on a trivially simple way of doing it and I'd like to share this with the stack overflow community. I was googling for the better part of an hour and was unable to actually find a good tutorial or .NET-ish example that felt right, hopefully this can be of use to other people out there.
It's actually incredibly simple, once you know about the semantics of lock and Monitor.
But first, you do need an object reference. You can use this, but remember that this is public, in the sense that anyone with a reference to your class can lock on that reference. If you are uncomfortable with this, you can create a new private reference, like this:
readonly object syncPrimitive = new object(); // this is legal
Somewhere in your code where you'd like to be able to provide notifications, it can be accomplished like this:
void Notify()
{
lock (syncPrimitive)
{
Monitor.Pulse(syncPrimitive);
}
}
And the place where you'd do the actual work is a simple looping construct, like this:
void RunLoop()
{
lock (syncPrimitive)
{
for (;;)
{
// do work here...
Monitor.Wait(syncPrimitive);
}
}
}
Yes, this looks incredibly deadlock-ish, but the locking protocol for Monitor is such that it will release the lock during the Monitor.Wait. In fact, it's a requirement that you have obtained the lock before you call either Monitor.Pulse, Monitor.PulseAll or Monitor.Wait.
There's one caveat with this approach that you should know about. Since the lock is required to be held before calling the communication methods of Monitor you should really only hang on to the lock for an as short duration as possible. A variation of the RunLoop that's more friendly towards long running background tasks would look like this:
void RunLoop()
{
for (;;)
{
// do work here...
lock (syncPrimitive)
{
Monitor.Wait(syncPrimitive);
}
}
}
But now we've changed up the problem a bit, because the lock is no longer protecting the shared resource throughout the processing. So, if some of your code in the do work here... bit needs to access a shared resource you'll need an separate lock managing access to that.
We can leverage the above to create a simple thread-safe producer consumer collection (although .NET already provides an excellent ConcurrentQueue<T> implementation; this is just to illustrate the simplicity of using Monitor in implementing such mechanisms).
class BlockingQueue<T>
{
// We base our queue on the (non-thread safe) .NET 2.0 Queue collection
readonly Queue<T> q = new Queue<T>();
public void Enqueue(T item)
{
lock (q)
{
q.Enqueue(item);
System.Threading.Monitor.Pulse(q);
}
}
public T Dequeue()
{
lock (q)
{
for (;;)
{
if (q.Count > 0)
{
return q.Dequeue();
}
System.Threading.Monitor.Wait(q);
}
}
}
}
Now the point here is not to build a blocking collection, that also available in the .NET framework (see BlockingCollection). The point is to illustrate how simple it is to build an event driven message system using the Monitor class in .NET to implement conditional variable. Hope you find this useful.
Use ManualResetEvent
The class that is similar to conditional variable is the ManualResetEvent, just that the method name is slightly different.
The notify_one() in C++ would be named Set() in C#.
The wait() in C++ would be named WaitOne() in C#.
Moreover, ManualResetEvent also provides a Reset() method to set the state of the event to non-signaled.
The accepted answer is not a good one.
According to the Dequeue() code, Wait() gets called in each loop, which causes unnecessary waiting thus excessive context switches. The correct paradigm should be, wait() is called when the waiting condition is met. In this case, the waiting condition is q.Count() == 0.
Here's a better pattern to follow when it comes to using a Monitor.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682052%28v=vs.85%29.aspx
Another comment on C# Monitor is, it does not make use of a condition variable(which will essentially wake up all threads waiting for that lock, regardless of the conditions in which they went to wait; consequently, some threads may grab the lock and immediately return to sleep when they find the waiting condition hasn't been changed). It does not provide you with as find-grained threading control as pthreads. But it's .Net anyway, so not completely unexpected.
=============upon the request of John, here's an improved version=============
class BlockingQueue<T>
{
readonly Queue<T> q = new Queue<T>();
public void Enqueue(T item)
{
lock (q)
{
while (false) // condition predicate(s) for producer; can be omitted in this particular case
{
System.Threading.Monitor.Wait(q);
}
// critical section
q.Enqueue(item);
}
// generally better to signal outside the lock scope
System.Threading.Monitor.Pulse(q);
}
public T Dequeue()
{
T t;
lock (q)
{
while (q.Count == 0) // condition predicate(s) for consumer
{
System.Threading.Monitor.Wait(q);
}
// critical section
t = q.Dequeue();
}
// this can be omitted in this particular case; but not if there's waiting condition for the producer as the producer needs to be woken up; and here's the problem caused by missing condition variable by C# monitor: all threads stay on the same waiting queue of the shared resource/lock.
System.Threading.Monitor.Pulse(q);
return t;
}
}
A few things I'd like to point out:
1, I think my solution captures the requirements & definitions more precisely than yours. Specifically, the consumer should be forced to wait if and only if there's nothing left in the queue; otherwise it's up to the OS/.Net runtime to schedule threads. In your solution, however, the consumer is forced to wait in each loop, regardless whether it has actually consumed anything or not - this is the excessive waiting/context switches I was talking about.
2, My solution is symmetric in the sense that both the consumer and the producer code share the same pattern while yours is not. If you did know the pattern and just omitted for this particular case, then I take back this point.
3, Your solution signals inside the lock scope, while my solutions signals outside the lock scope. Please refer to this answer as to why your solution is worse.
why should we signal outside the lock scope
I was talking about the flaw of missing condition variables in C# monitor, and here's its impact: there's simply no way for C# to implemented the solution of moving the waiting thread from the condition queue to the lock queue. Therefore, the excessive context switch is doomed to take place in the three-thread scenario proposed by the answer in the link.
Also, the lack of condition variable makes it impossible to distinguish between the various cases where threads wait on the same shared resource/lock, but for different reasons. All waiting threads are place on a big waiting queue for that shared resource, which undermines efficiency.
"But it's .Net anyway, so not completely unexpected" --- it's understandable that .Net does not pursue as high efficiency as C++, it's understandable. But it does not imply programmers should not know the differences and their impacts.
Go to deadlockempire.github.io/. They have an amazing tutorial that will help you understand the condition variable as well as locks and will cetainly help you write your desired class.
You can step through the following code at deadlockempire.github.io and trace it. Here is the code snippet
while (true) {
Monitor.Enter(mutex);
if (queue.Count == 0) {
Monitor.Wait(mutex);
}
queue.Dequeue();
Monitor.Exit(mutex);
}
while (true) {
Monitor.Enter(mutex);
if (queue.Count == 0) {
Monitor.Wait(mutex);
}
queue.Dequeue();
Monitor.Exit(mutex);
}
while (true) {
Monitor.Enter(mutex);
queue.Enqueue(42);
Monitor.PulseAll(mutex);
Monitor.Exit(mutex);
}
As has been pointed out by h9uest's answer and comments the Monitor's Wait interface does not allow for proper condition variables (i.e. it does not allow for waiting on multiple conditions per shared lock).
The good news is that the other synchronization primitives (e.g. SemaphoreSlim, lock keyword, Monitor.Enter/Exit) in .NET can be used to implement a proper condition variable.
The following ConditionVariable class will allow you to wait on multiple conditions using a shared lock.
class ConditionVariable
{
private int waiters = 0;
private object waitersLock = new object();
private SemaphoreSlim sema = new SemaphoreSlim(0, Int32.MaxValue);
public ConditionVariable() {
}
public void Pulse() {
bool release;
lock (waitersLock)
{
release = waiters > 0;
}
if (release) {
sema.Release();
}
}
public void Wait(object cs) {
lock (waitersLock) {
++waiters;
}
Monitor.Exit(cs);
sema.Wait();
lock (waitersLock) {
--waiters;
}
Monitor.Enter(cs);
}
}
All you need to do is create an instance of the ConditionVariable class for each condition you want to be able to wait on.
object queueLock = new object();
private ConditionVariable notFullCondition = new ConditionVariable();
private ConditionVariable notEmptyCondition = new ConditionVariable();
And then just like in the Monitor class, the ConditionVariable's Pulse and Wait methods must be invoked from within a synchronized block of code.
T Take() {
lock(queueLock) {
while(queue.Count == 0) {
// wait for queue to be not empty
notEmptyCondition.Wait(queueLock);
}
T item = queue.Dequeue();
if(queue.Count < 100) {
// notify producer queue not full anymore
notFullCondition.Pulse();
}
return item;
}
}
void Add(T item) {
lock(queueLock) {
while(queue.Count >= 100) {
// wait for queue to be not full
notFullCondition.Wait(queueLock);
}
queue.Enqueue(item);
// notify consumer queue not empty anymore
notEmptyCondition.Pulse();
}
}
Below is a link to the full source code of a proper Condition Variable class using 100% managed code in C#.
https://github.com/CodeExMachina/ConditionVariable
i think i found "The WAY" on the tipical problem of a
List<string> log;
used by multiple thread, one tha fill it and the other processing and the other one empting
avoiding empty
while(true){
//stuff
Thread.Sleep(100)
}
variables used in Program
public static readonly List<string> logList = new List<string>();
public static EventWaitHandle evtLogListFilled = new AutoResetEvent(false);
the processor work like
private void bw_DoWorkLog(object sender, DoWorkEventArgs e)
{
StringBuilder toFile = new StringBuilder();
while (true)
{
try
{
{
//waiting form a signal
Program.evtLogListFilled.WaitOne();
try
{
//critical section
Monitor.Enter(Program.logList);
int max = Program.logList.Count;
for (int i = 0; i < max; i++)
{
SetText(Program.logList[0]);
toFile.Append(Program.logList[0]);
toFile.Append("\r\n");
Program.logList.RemoveAt(0);
}
}
finally
{
Monitor.Exit(Program.logList);
// end critical section
}
try
{
if (toFile.Length > 0)
{
Logger.Log(toFile.ToString().Substring(0, toFile.Length - 2));
toFile.Clear();
}
}
catch
{
}
}
}
catch (Exception ex)
{
Logger.Log(System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
Thread.Sleep(100);
}
}
On the filler thread we have
public static void logList_add(string str)
{
try
{
try
{
//critical section
Monitor.Enter(Program.logList);
Program.logList.Add(str);
}
finally
{
Monitor.Exit(Program.logList);
//end critical section
}
//set start
Program.evtLogListFilled.Set();
}
catch{}
}
this solution is fully tested, the istruction Program.evtLogListFilled.Set(); may release the lock on Program.evtLogListFilled.WaitOne() and also the next future lock.
I think this is the simpliest way.
I have a method named InitializeCRMService() which returns an object of IOrganizationService. Now I am defining a different method named GetConnection(string thread) which calls InitializeCRMService() based on the parameter passed to it. If the string passed to GetConnection is single it will start a single threaded instance of the IntializeCRMService() method, but if the string passed is multiple, I need to use a thread pool where I need to pass the method to QueueUserWorkItem. The method InitializeCRMService has no input parameters. It just returns a service object. Please find below the code block in the GetConnection method:
public void GetConnection(string thread)
{
ParallelOptions ops = new ParallelOptions();
if(thread.Equals("one"))
{
Parallel.For(0, 1, i =>
{
dynamic serviceObject = InitializeCRMService();
});
}
else if (thread.Equals("multi"))
{
// HERE I NEED TO IMPLEMENT MULTITHREADING USING THREAD POOL
// AND NOT PARALLEL FOR LOOP......
// ThreadPool.QueueUserWorkItem(new WaitCallback(InitializeCRMService));
}
}
Please note my method InitializeCRMService() has a return type of Service Object.
Please tell me how do I implement it.
Since you want to execute InitializeCRMService in the ThreadPool when a slot is available, and you are executing this only once, the solution depends on what you want to do with the return value of InitializeCRMService.
If you only want to ignore it, I have two options so far.
Option 1
public void GetConnection(string thread)
{
//I found that ops is not being used
//ParallelOptions ops = new ParallelOptions();
if(thread.Equals("one"))
{
Parallel.For(0, 1, i =>
{
//You don't really need to have a variable
/*dynamic serviceObject =*/ InitializeCRMService();
});
}
else if (thread.Equals("multi"))
{
ThreadPool.QueueUserWorkItem
(
new WaitCallback
(
(_) =>
{
//You don't really need to have a variable
/*dynamic serviceObject =*/ InitializeCRMService();
}
)
);
}
}
On the other hand, if you need to pass it somewhere to store it an reuse it later you can do it like this:
public void GetConnection(string thread)
{
//I found that ops is not being used
//ParallelOptions ops = new ParallelOptions();
if(thread.Equals("one"))
{
Parallel.For(0, 1, i =>
{
//It seems to me a good idea to take the same path here too
//dynamic serviceObject = InitializeCRMService();
Store(InitializeCRMService());
});
}
else if (thread.Equals("multi"))
{
ThreadPool.QueueUserWorkItem
(
new WaitCallback
(
(_) =>
{
Store(InitializeCRMService());
}
)
);
}
}
Where Store would be something like this:
private void Store(dynamic serviceObject)
{
//store serviceObject somewhere you can use it later.
//Depending on your situation you may want to
// set a flag or use a ManualResetEvent to notify
// that serviceObject is ready to be used.
//Any pre proccess can be done here too.
//Take care of thread affinity,
// since this may come from the ThreadPool
// and the consuming thread may be another one,
// you may need some synchronization.
}
Now, if you need to allow clients of your class to access serviceObject, you can take the following approach:
//Note: I marked it as partial because there may be other code not showed here
// in particular I will not write the method GetConnection again. That said...
// you can have it all in a single block in a single file without using partial.
public partial class YourClass
{
private dynamic _serviceObject;
private void Store(dynamic serviceObject)
{
_serviceObject = serviceObject;
}
public dynamic ServiceObject
{
get
{
return _serviceObject;
}
}
}
But this doesn't take care of all the cases. In particular if you want to have thread waiting for serviceObject to be ready:
public partial class YourClass
{
private ManualResetEvent _serviceObjectWaitHandle = new ManualResetEvent(false);
private dynamic _serviceObject;
private void Store(dynamic serviceObject)
{
_serviceObject = serviceObject;
//If you need to do some work as soon as _serviceObject is ready...
// then it can be done here, this may still be the thread pool thread.
//If you need to call something like the UI...
// you will need to use BeginInvoke or a similar solution.
_serviceObjectWaitHandle.Set();
}
public void WaitForServiceObject()
{
//You may also expose other overloads, just for convenience.
//This will wait until Store is executed
//When _serviceObjectWaitHandle.Set() is called
// this will let other threads pass.
_serviceObjectWaitHandle.WaitOne();
}
public dynamic ServiceObject
{
get
{
return _serviceObject;
}
}
}
Still, I haven't covered all the scenarios. For intance... what happens if GetConnection is called multiple times? We need to decide if we want to allow that, and if we do, what do we do with the old serviceObject? (do we need to call something to dismiss it?). This can be problematic, if we allow multiple threads to call GetConnection at once. So by default I will say that we don't, but we don't want to block the other threads either...
The solution? Follows:
//This is another part of the same class
//This one includes GetConnection
public partial class YourClass
{
//1 if GetConnection has been called, 0 otherwise
private int _initializingServiceObject;
public void GetConnection(string thread)
{
if (Interlocked.CompareExchange(ref _initializingServiceObject, 1, 0) == 0)
{
//Go on, it is the first time GetConnection is called
//I found that ops is not being used
//ParallelOptions ops = new ParallelOptions();
if(thread.Equals("one"))
{
Parallel.For(0, 1, i =>
{
//It seems to me a good idea to take the same path here too
//dynamic serviceObject = InitializeCRMService();
Store(InitializeCRMService());
});
}
else if (thread.Equals("multi"))
{
ThreadPool.QueueUserWorkItem
(
new WaitCallback
(
(_) =>
{
Store(InitializeCRMService());
}
)
);
}
}
}
}
Finally, if we are allowing multiple thread to use _serviceObject, and _serviceObject is not thread safe, we can run into trouble. Using monitor or using a read write lock are two alternatives to solve that.
Do you remember this?
public dynamic ServiceObject
{
get
{
return _serviceObject;
}
}
Ok, you want to have the caller access the _serviceObject when it is in a context that will prevent others thread to enter (see System.Threading.Monitor), and make sure it stop using it, and then leave this context I mentioned before.
Now consider that the caller thread could still store a copy of _serviceObject somewhere, and then leave the syncrhonization, and then do something with _serviceObject, and that may happen when another thread is using it.
I'm used to think of every corner case when it comes to threading. But if you have control over the calling threads, you can do it very well with just the property showed above. If you don't... let's talk about it, I warn you, it can be extensive.
Option 2
This is a totally different behaviour, the commend Damien_The_Unbeliever made in your question made me think that you may have intended to return serviceObject. In that case, it is not shared among threads, and it is ok to have multiple serviceObject at a time. And any synchronization needed is left to the caller.
Ok, this may be what you have been looking for:
public void GetConnection(string thread, Action<dynamic> callback)
{
if (ReferenceEquals(callback, null))
{
throw new ArgumentNullException("callback");
}
//I found that ops is not being used
//ParallelOptions ops = new ParallelOptions();
if(thread.Equals("one"))
{
Parallel.For(0, 1, i =>
{
callback(InitializeCRMService());
});
}
else if (thread.Equals("multi"))
{
ThreadPool.QueueUserWorkItem
(
new WaitCallback
(
(_) =>
{
callback(InitializeCRMService());
}
)
);
}
}
How should the callback look? Well, as soon as it is not shared between threads it is ok. Why? Because each thread that calls GetConnection passes it's own callback Action, and will recieve a different serviceObject, so there is no risk that what one thread does to it affect what the other does to its (since it is not the same serviceObject).
Unless you want to have one thread call this and then shared it with other threads, in which case, it is a problem of the caller and it will be resolved in another place in another moment.
One last thing, you could use an enum to represent the options you currently pass in the string thread. In fact, since there are only two options you may consider using a bool, unless they may appear more cases in the future.
I am trying to bypass the the wait64 handle limit that .net 3.5 imposes
I have seen this thread : Workaround for the WaitHandle.WaitAll 64 handle limit?
So I understand the general idea but I am having difficulty because I am not using a delegate but rather
I am basically working of this example :
http://msdn.microsoft.com/en-us/library/3dasc8as%28VS.80%29.aspx
This link http://www.switchonthecode.com/tutorials/csharp-tutorial-using-the-threadpool
is similar but again the int variable keeping track of the tasks is a member variable.
Where in the above example would I pass the threadCount integer?
Do I pass it in the callback method as an object? I think I am having trouble with the callback method and passing by reference.
Thanks Stephen,
That link is not entirely clear to me.
Let me post my code to help myself clarify:
for (int flows = 0; flows < NumFlows; flows++)
{
ResetEvents[flows] = new ManualResetEvent(false);
ICalculator calculator = new NewtonRaphson(Perturbations);
Calculators[flows] = calculator;
ThreadPool.QueueUserWorkItem(calculator.ThreadPoolCallback, flows);
}
resetEvent.WaitOne();
Where would I pass in my threadCount variable. I assume it needs to be decremented in calculator.ThreadPoolCallback?
You should not be using multiple wait handles to wait for the completion of multiple work items in the ThreadPool. Not only is it not scalable you will eventually bump into the 64 handle limit imposed by the WaitHandle.WaitAll method (as you have done already). The correct pattern to use in this situation is a counting wait handle. There is one available in the Reactive Extensions download for .NET 3.5 via the CountdownEvent class.
var finished = new CountdownEvent(1);
for (int flows = 0; flows < NumFlows; flows++)
{
finished.AddCount();
ICalculator calculator = new NewtonRaphson(Perturbations);
Calculators[flows] = calculator;
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
calculator.ThreadPoolCallback(state);
}
finally
{
finished.Signal();
}
}, flows);
}
finished.Signal();
finished.Wait();
An anonymous method might be easiest:
int threadCount = 0;
for (int flows = 0; flows < NumFlows; flows++)
{
ICalculator calculator = new NewtonRaphson(Perturbations);
Calculators[flows] = calculator;
// We're about to queue a new piece of work:
// make a note of the fact a new work item is starting
Interlocked.Increment(ref threadCount);
ThreadPool.QueueUserWorkItem(
delegate
{
calculator.ThreadPoolCallback(flows);
// We've finished this piece of work...
if (Interlocked.Decrement(ref threadCount) == 0)
{
// ...and we're the last one.
// Signal back to the main thread.
resetEvent.Set();
}
}, null);
}
resetEvent.WaitOne();