Parallel.Invoke and thread invocation - Clarification? - c#

I have this code which creates a deadlock :
void Main()
{
ClassTest test = new ClassTest();
lock(test)
{
Task t1 = new Task(() => test.DoWorkUsingThisLock(1));
t1.Start();
t1.Wait();
}
}
public class ClassTest
{
public void DoWorkUsingThisLock(int i)
{
Console.WriteLine("Before " + i);
Console.WriteLine ("Current Thread ID is = "+Thread.CurrentThread.ManagedThreadId);
lock(this)
{
Console.WriteLine("Work " + i);
Thread.Sleep(1000);
}
Console.WriteLine("Done " + i);
}
}
Result :
Before 1
(and deadlock....)
I know that this is a bad practice to lock over instances beyond code's control or , this. But it's just for this question.
I can understand why a deadlock is created here.
The main thread acquires the lock(test) in main and then a new thread starts to invoke DoWorkUsingThisLock - there it tries to acquire a lock over the same instance variable and it's stuck ( because of t1.Wait() at main)
OK
But I've seen this answer here which also creates deadlock.
void Main()
{
ClassTest test = new ClassTest();
lock(test)
{
Parallel.Invoke (
() => test.DoWorkUsingThisLock(1),
() => test.DoWorkUsingThisLock(2)
);
}
}
public class ClassTest
{
public void DoWorkUsingThisLock(int i)
{
Console.WriteLine("Before ClassTest.DoWorkUsingThisLock " + i);
lock(this)
{
Console.WriteLine("ClassTest.DoWorkUsingThisLock " + i);
Thread.Sleep(1000);
}
Console.WriteLine("ClassTest.DoWorkUsingThisLock Done " + i);
}
}
The result is :
Before ClassTest.DoWorkUsingThisLock 1
Before ClassTest.DoWorkUsingThisLock 2
ClassTest.DoWorkUsingThisLock 1 // <---- how ?
ClassTest.DoWorkUsingThisLock Done 1
Question:
How come it DID acquire the lock for the first invocation (DoWorkUsingThisLock(1))? The lock at main is still blocked due to Parallel.Invoke which DOES block !
I don't understand how the thread has succeeded to enter the lock(this) section.

The Parallel class uses the current thread to do a part of the work. This is a nice performance optimization but it is observable in the case of thread-specific state.
The TPL has this kind of "inline execution" in many places and it causes a lot of trouble in different ways. Many programs are not made to deal with reentrancy.

Related

Interrupt calling thread when exception in child task

I have the following scenario:
I have a plugin class (unfortunately synchronous and that's out of my control) which runs automation scripts. At startup, a task is started which runs in the background continuously until the user stops it. As this task runs, it is parsing streaming incoming data from a serial port and continuously updating a list of responses. In parallel, the script will be changing some other values and monitoring how the responses react.
My problem is this -- it is possible that the parser could throw an exception and that renders any of the remaining script invalid. But, I can't find a good way to interrupt the script (i.e. void Main() below) should this parallel task throw. If I wait until my script is done, and then await the task, I do get the exception, but by then there is potentially a lot of time wasted. So I'm looking for better ways to interrupt the script that is running should the parallel task error. I've tried posting on the initial synchronization context but with no luck as well. I've parred down an example below to simulate a similar scenario
public class Test : TestPlugin
{
Task _t;
List<string> data = new List();
public Test(){ }
public override void Cleanup()
{
//_t.Wait();
}
public override void Main()
{
// i want this to be interrupted if the polling task started in startup throws.
//Right here simulates running test steps,
//any of which can access the data that's been updated by the "background" task at any time
try
{
int i = 0;
while (i < 10)
{
Task.Delay(1000).Wait();
Console.WriteLine("step" + i + "Latest: " + data.latest());
i++;
}
}
catch(Exception ex)
{
Console.WriteLine("EXCEPTION");
}
}
public override void Setup()
{
_t = Task.Run(async () =>
{
int i =0;
while (i < 10)
{
await Task.Delay(200);
Console.WriteLine(i);
i++;
//i would parse incoming data and add to array here
data.add(i);
if (i > 3) throw new Exception("UH OH");
}
});
}
}
You could investigate the Task.ContinueWith method on the calling task code.
this ContinueWith allows for a delegate callback that gets triggered on completion and/or exceptions. so perhaps within the ContinueWith delegate, do a check if the task completes successfully, if not then raise a new exception there appending the thrown exception passed to the delegate.
You can use the code below as an example:
Task t1 = factory.StartNew(() =>
{
DoSomething();
}).ContinueWith((t2) =>
{
if (t2.IsCanceled)
DoSomethingWhenCancelled();
else if (t2.IsFaulted)
DoSomethingOnError(t1.Exception);
else
DoSomethingWhenComplete();
});
I think I am going to have to end up with something like the following. Unfortunately this forces developers of these test procedures to need to wrap all test steps that execute in parallel to the serial port reader with a task, but maybe it's possible for me to abstract away that implementation detail into a class with an API that manages this a bit better for them.
public override void Main()
{
Task steps = Task.Run(async () =>
{
int i = 1;
//this represents step 1
await Task.Delay(5000);
i++;
Console.WriteLine("Step " + i);
//this represents step 2
await Task.Delay(5000);
i++;
Console.WriteLine("Step " + i);
//this represents step 3
await Task.Delay(5000);
i++;
Console.WriteLine("Step " + i);
//this represents step 4
await Task.Delay(5000);
i++;
Console.WriteLine("Step " + i);
});
Task.WaitAny(_t, steps);
}

C# Multithread dequeue List<string>

First of all, sorry for my english. I'm doing some C# exercices but I'm in a trouble with this.
Actually, I need to create 2 threads using Thread class. These threads needs to Dequeue items from a List (I have created a Dequeue method to do that) but I need to configure these 2 threads to Deqeueue this List at the same time. Aditionaly, this method needs to show the thread that executed him and the removed the object.
That's the method called by Thread:
private static object Lock = new object();
public string Consume()
{
string result = "";
while (StringList.Count > 0)
{
lock (Lock)
{
result = Dequeue();
}
}
return result;
}
And the thread call:
Thread t1 = new Thread(() => { Console.WriteLine("Thread 1: " + QC.Consume()); });
Thread t2 = new Thread(() => { Console.WriteLine("Thread 2: " + QC.Consume()); });
t1.Start();
t2.Start();
Actually, the program "is working" but it is only being executed by an unique thread. I don't know how to dequeue items from list at the same time with different threads + show which thread dequeued the item.
I'm not asking just to know if someone know the problem, I want to understand the problem and solve it.
Thanks to all!

how to transfer some info to other?

I have two threads. How to get data from thread1 to thread2. It means, whe thread1 has done its work, it has some data, and this data must be used in the second "thread2". How to realize it ?
Here is code, but what to do..now ?
static void Main(string[] args)
{
Thread t1 = new Thread(thread1);
t1.Start();
Thread t2 = new Thread(thread2);
t2.Start();
}
static void thread1()
{
string newstring="123";
}
static void thread2()
{
//what to do here...what code will be here?
Console.WriteLine(newstring);
}
In thread1 can be whatever, but i need to get this "whatever", than i can use it in thread2
Data, which is used by both Thread must be commonly shared between both thread.
usually it is called common resource.
One this you must note that you have to achieve synchronization here.
As both threads are running independently and also reading/writing common data, chances of Race Condition is pretty high. To prevent such cases, you must implement synchronization on reading/writing data (on common object).
refere below code, where CommonResource is common between both threads and synchronization has been achieved by locking
In your example, one thread is writing data and other thread is reading data. If we don't implement Synchronization, there are chances that while thread 1 is writing new data, but thread 2 (because it is not waiting for thread 1 to complete it's task first) will bring old data (or invalid data).
Situation goes worst when there are multiple threads which are writing data, without waiting for other threads to complete their writing.
public class CommonResourceClass
{
object lockObj;
//Note: here main resource is private
//(thus not in scope of any thread)
string commonString;
//while prop is public where we have lock
public string CommonResource
{
get
{
lock (lockObj)
{
Console.WriteLine(DateTime.Now.ToString() + " $$$$$$$$$$$$$$$ Reading");
Thread.Sleep(1000 * 2);
return commonString;
}
}
set
{
lock (lockObj)
{
Console.WriteLine(DateTime.Now.ToString() + " ************* Writing");
Thread.Sleep(1000 * 5);
commonString = value;
}
}
}
public CommonResourceClass()
{
lockObj = new object();
}
}
and Thread calling be like
static CommonResourceClass commonResourceClass;
static void Main(string[] args)
{
commonResourceClass = new CommonResourceClass();
Thread t1 = new Thread(ThreadOneRunner);
Thread t2 = new Thread(ThreadTwoRunner);
t1.Start();
t2.Start();
}
static void ThreadOneRunner()
{
while(true)
{
Console.WriteLine(DateTime.Now.ToString() + " *******Trying To Write");
commonResourceClass.CommonResource = "Written";
Console.WriteLine(DateTime.Now.ToString() + " *******Writing Done");
}
}
static void ThreadTwoRunner()
{
while(true)
{
Console.WriteLine(DateTime.Now.ToString() + " $$$$$$$Trying To Read");
string Data = commonResourceClass.CommonResource;
Console.WriteLine(DateTime.Now.ToString() + " $$$$$$$Reading Done");
}
}
Output of it:
Note That, reading is taking 2 seconds and writing is taking 5 seconds, so reading is supposed to be faster. But if writing is going on, reading must wait till writing done.
you can clearly see in output, as one thread is trying to read or write, it cannot do it while other thread is performing it's task.

Calling one non thread-safe method in a thread from another thread

Suppose I have a non thread-safe Class X on the main thread and I have another class Y which is in another thread and needs to call a method doX() of Class X.
I would simply pass a reference of Class X to Class Y and call doX() from Y however this class X is non thread-safe and if called from another thread behaves weirdly.
How can I let Y call method doX() of X from X's thread? in the SSCC below the managedthreadid should always be the same (but it isn't).
using System;
using System.Threading;
namespace ThreadApp
{
static class Program
{
[STAThread]
static void Main()
{
int managedThreadId = Thread.CurrentThread.ManagedThreadId;
System.Diagnostics.Debug.WriteLine("Main ManagedThreadId = " + managedThreadId);
X x = new X();
x.doX();
Y y = new Y();
y.fun(x);
}
}
class X
{
public void doX()
{
int managedThreadId = Thread.CurrentThread.ManagedThreadId;
System.Diagnostics.Debug.WriteLine("X ManagedThreadId = " + managedThreadId);
}
}
class Y
{
public void fun(X x)
{
Thread t = new Thread(x.doX);
t.Start();
}
}
}
EDIT: This page explains my problem better than I can: http://mikehadlow.blogspot.it/2012/11/using-blockingcollection-to-communicate.html
Consider these (somewhat) common programming challenges:
I’m using a third party library that is not thread safe, but I want my
application to share work between multiple threads. How do I marshal
calls between my multi-threaded code to the single threaded library? I
have a single source of events on a single thread, but I want to share
the work between a pool of multiple threads? I have multiple threads
emitting events, but I want to consume them on a single thread? One
way of doing this would be to have some shared state, a field or a
property on a static class, and wrap locks around it so that multiple
threads can access it safely. This is a pretty common way of trying to
skin this particular cat, but it’s shot through with traps for the
unwary. Also, it can hurt performance because access to the shared
resource is serialized, even though the things accessing it are
running in parallel.
A better way is to use a BlockingCollection and have your threads
communicate via message classes.
Here's a working solution based on that website suggestion of using BlockingCollection:
namespace ThreadApp
{
static class Program
{
[STAThread]
static void Main()
{
int managedThreadId = Thread.CurrentThread.ManagedThreadId;
System.Diagnostics.Debug.WriteLine("Main ManagedThreadId = " + managedThreadId);
X x = new X();
Y y = new Y();
y.fun(x);
x.doX();
}
}
class X
{
private BlockingCollection<String> queue = new BlockingCollection<String>();
public void Produce(String item)
{
queue.Add(item);
}
public void doX()
{
while (true)
{
String item = queue.Take();
int managedThreadId = Thread.CurrentThread.ManagedThreadId;
System.Diagnostics.Debug.WriteLine("X ManagedThreadId = " + managedThreadId + " randomid=" + item);
// Add your code to process the item here.
// Do not start another task or thread.
}
}
}
class Y
{
X x;
public void fun(X x)
{
this.x = x;
Thread t = new Thread(threadBody);
t.Start();
}
void threadBody()
{
while (true)
{
int managedThreadId = Thread.CurrentThread.ManagedThreadId;
Random rand = new Random();
int randInt = rand.Next(1, 90);
System.Diagnostics.Debug.WriteLine("Y ManagedThreadId = " + managedThreadId + " random-int" + randInt);
x.Produce("random-int" + randInt);
Thread.Sleep(randInt * 10);
}
}
}
}
The above solution works, here's the output:
Main ManagedThreadId = 1
Y ManagedThreadId = 3 random-int24
X ManagedThreadId = 1 randomid=random-int24
Y ManagedThreadId = 3 random-int46
X ManagedThreadId = 1 randomid=random-int46
Y ManagedThreadId = 3 random-int48
X ManagedThreadId = 1 randomid=random-int48
The Y thread inserts a random-int and the X thread receives it in the queue and executes its method in the same thread as the Main thread.
However the problem is the doX() method is inside a while loop so it is blocking. If I have an X class which has some other functions to do and cannot block looping inside a method this approach would not work...
Here's an awesome approach. Use Microsoft's Reactive Framework (Rx).
Rx primarily provides an observable/observer model that is extremely powerful, but it also provides a set of schedulers that can be used to simply work with threads. The EventLoopScheduler scheduler can be used to ensure that code runs on a single thread.
Try this example:
var els = new System.Reactive.Concurrency.EventLoopScheduler();
Console.WriteLine("A" + Thread.CurrentThread.ManagedThreadId);
els.Schedule(() =>
{
Console.WriteLine("B" + Thread.CurrentThread.ManagedThreadId);
});
var thread = new Thread((ThreadStart)(() =>
{
Console.WriteLine("C" + Thread.CurrentThread.ManagedThreadId);
els.Schedule(() =>
{
Console.WriteLine("D" + Thread.CurrentThread.ManagedThreadId);
});
}));
thread.Start();
It outputs:
A12
B14
C16
D14
Both "B" and "D" run on the same thread even though the call to schedule an action came from two different threads.
You can use an EventLoopScheduler to make sure you code on X runs on the same thread.
Just NuGet "System.Reactive" to get the bits.

How to maintain Thread context across async await model in C#?

Is using ThreadStatic and setting the context every time await completes "an option"? Is there another way?
public async void Test()
{
// This is in Thread 1
Foo foo = new Foo();
Context.context = "context1"; // This is ThreadStatic
string result = await foo.CallAsynx();
// This is most likely Thread 2
Context.context = "context1"; // This might be a different thread and so resetting context
}
Now is there another way if I don't want to use ThreadStatic?
ThreadStatic, ThreadLocal<T>, thread data slots, and CallContext.GetData / CallContext.SetData do not work well with async, since they are thread-specific.
The best alternatives are:
Passing it as an argument as #PauloMorgado suggested. Equivalently, you could set it as a field member of an object (it's implicitly passed as an argument via this); or you could have your lambdas capture the variable (underneath, the compiler will implicitly pass it as an argument via this).
Use HttpContext.Items (if you are on ASP.NET 4.5).
Use CallContext.LogicalGetData / CallContext.LogicalSetData as #Noseratio suggested. You can only store immutable data in the logical thread context; and it only works on .NET 4.5 and is not available on all platforms (e.g., Win8).
Force all async continuations back to the same thread by installing a "main loop" for that thread, such as the AsyncContext from my AsyncEx library.
Just if someone has the same question some years later and finds this thread...
There is a new feature called
AsyncLocal<T>
https://learn.microsoft.com/en-us/dotnet/api/system.threading.asynclocal-1?view=netcore-3.1
This works with "async/await" and also with:
Task.Run(...)
Dispatcher.BeginInvoke(...)
new Thread(...).Start()
I just testet those three with the following code:
private void StartTests() {
Thread.Sleep(1000);
Task.Run(() => DoWork1());
Task.Run(() => DoWork2());
}
private void DoWork1() {
ThreadContext.Context.Value = "Work 1";
Thread.Sleep(5);
Task.Run(() => PrintContext("1"));
Thread.Sleep(10);
Dispatcher.BeginInvoke(new Action(() => PrintContext("1")));
Thread.Sleep(15);
var t = new Thread(() => PrintContextT("1"));
t.Start();
}
private void DoWork2() {
ThreadContext.Context.Value = "Work 2";
Task.Run(() => PrintContext("2"));
Thread.Sleep(10);
Dispatcher.BeginInvoke(new Action(() => PrintContext("2")));
Thread.Sleep(10);
var t = new Thread(() => PrintContextT("2"));
t.Start();
}
private void PrintContext(string c) {
var context = ThreadContext.Context.Value;
Console.WriteLine("P: " + context + "-" + c);
Task.Run(() => PrintContext2(c));
}
private void PrintContext2(string c) {
Thread.Sleep(7);
var context = ThreadContext.Context.Value;
Console.WriteLine("P2: " + context + "-" + c);
}
private void PrintContextT(string c) {
var context = ThreadContext.Context.Value;
Console.WriteLine("T: " + context + "-" + c);
}
public class ThreadContext {
public static AsyncLocal<object> Context = new AsyncLocal<object>();
}
Output:
P: Work 2-2
P: Work 1-1
P2: Work 2-2
P: Work 2-2
P2: Work 1-1
P: Work 1-1
P2: Work 2-2
T: Work 2-2
P2: Work 1-1
T: Work 1-1

Categories

Resources