How to execute code asynchronously in separate domains ?
For example, I have a method :
public void DoSomething()
{
// do something
}
And I want to execute it in 10 different domains, like this :
for (int i = 0; i < 10; i++)
{
AppDomain domain = AppDomain.CreateDomain("NewDomain - " + i);
domain.ExecuteAsync(DoSomething);
}
I solved my task using this approach :
for (int i = 0; i < options.NumberOfThreads; i++)
{
tasks[i] = Task.Factory.StartNew(() =>
{
using (Isolated<TesterInvoker> isolated = new Isolated<TesterInvoker>())
{
isolated.Value.Invoke();
}
});
}
private class TesterInvoker : MarshalByRefObject
{
public void Invoke()
{
// do something
}
}
private class Isolated<T> : IDisposable
where T : MarshalByRefObject
{
private AppDomain _domain;
private T _value;
public Isolated()
{
Type type = typeof(T);
_domain = AppDomain.CreateDomain("Isolated:" + GetHashCode(),
null, AppDomain.CurrentDomain.SetupInformation);
_value = (T)_domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
}
public T Value
{
get
{
return _value;
}
}
public void Dispose()
{
if (_domain != null)
{
AppDomain.Unload(_domain);
_domain = null;
}
}
}
Related
I developed an MPI test program where the master node distributes work to the worker nodes.
The worker node uses comm.Send() to request work and the master node checks with comm.ImmediateProbe if any of the worker nodes wants to request some work. If a request is available it is read with comm.Receive and the work is sent to the worker for processing.
When I run my test program with mpiexec.exe on a single host, either localhost or also a remote host everything works as expected, but when I run it on two hosts at the same time
the Send on the remote host blocks and the master nodes ImmediateProbe never receives the message sent from the worker on the remote host.
I run the program with mpiexec.exe -wdir \\DESKTOP-58QONBS\MPITest -hosts 2 DESKTOP-58QONBS 2 LAPTOP-L8F7AN5R 1 MPITest.exe
I'm new to MPI, so maybe I am doing something wrong I just could not figure out yet why the behaviour is like this when using two hosts at the same time.
The full code is below:
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
namespace MPITest
{
public abstract class MPIMasterWorkerBase<TWork, TResult>
where TWork : class
where TResult : class
{
protected abstract void Initialize(bool isMaster);
protected abstract void Main();
protected abstract void ProcessResult(TResult result);
protected abstract TResult ProcessWork(TWork work);
protected abstract TWork GetWork();
private volatile bool terminate = false;
private Thread thread;
private MPI.Intracommunicator comm;
public void Run(string[] args)
{
MPI.Environment.Run(ref args, comm =>
{
this.comm = comm;
if (comm.Size < 2)
{
Console.WriteLine("At least 2 processes are required.");
return;
}
if (comm.Rank == 0)
{
Initialize(isMaster: true);
thread = new Thread(MasterThread);
thread.Start();
Main();
terminate = true;
thread.Join();
}
else
{
Initialize(isMaster: false);
thread = new Thread(WorkerThread);
thread.Start();
thread.Join();
}
});
}
private void MasterThread()
{
Console.WriteLine($"MasterStart {MPI.Environment.ProcessorName}");
var done = new bool[comm.Size];
done[0] = true;
while (!done.All(x => x == true))
{
for (int i = 1; i < comm.Size; i++)
{
if (comm.ImmediateProbe(i, 0) != null)
{
Console.WriteLine($"Receive: {i}");
comm.Receive<int>(i, 0);
var work = GetWork();
if (work != null)
{
comm.Send(1, i, 0);
comm.Send(work, i, 0);
}
else
{
if (terminate)
{
comm.Send(-1, i, 0);
done[i] = true;
}
else
{
comm.Send(0, i, 0);
}
}
}
if (comm.ImmediateProbe(i, 1) != null)
{
var result = comm.Receive<TResult>(i, 1);
ProcessResult(result);
}
}
Thread.Sleep(1000);
}
Console.WriteLine("MasterStop");
}
private void WorkerThread()
{
Console.WriteLine($"WorkerStart: {comm.Rank} {MPI.Environment.ProcessorName}");
while (!terminate)
{
Thread.Sleep(1000);
Console.WriteLine($"Send: {comm.Rank}");
comm.Send(0, 0, 0);
var flag = comm.Receive<int>(0, 0);
if (flag == -1)
break;
else if (flag == 0)
continue;
var work = comm.Receive<TWork>(0, 0);
var result = ProcessWork(work);
comm.Send(result, 0, 1);
}
Console.WriteLine($"WorkerStop: {comm.Rank}");
}
}
[Serializable]
public class WorkItem
{
public int Id { get; set; }
}
public class MPITest : MPIMasterWorkerBase<WorkItem, WorkItem>
{
private ConcurrentQueue<WorkItem> queue = new();
private int id;
protected override void Initialize(bool isMaster)
{
}
protected override void Main()
{
var startTime = DateTime.UtcNow;
while ((DateTime.UtcNow - startTime).TotalSeconds < 10)
{
for (int i = 0; i < 2; i++)
queue.Enqueue(new WorkItem { Id = id++ });
Thread.Sleep(1000);
}
}
protected override WorkItem GetWork()
{
if (queue.TryDequeue(out var result))
return result;
return null;
}
protected override WorkItem ProcessWork(WorkItem work)
{
Console.WriteLine($"Processing Work {work.Id}");
return work;
}
protected override void ProcessResult(WorkItem result)
{
Console.WriteLine($"Process Result {result.Id}");
}
}
class Program
{
static void Main(string[] args)
{
new MPITest().Run(args);
}
}
}
The comm.Send was blocking, but after some minutes of waiting the program started to work.
The issues were caused by the VirtualBox Host-Only Network Adapter that was also installed on the system. Disabling this adapter in the network settings resolved all the issues.
So I want to be able to set all the variable to false except the Boolean referenced, but this variable varies so i cannot use the required 'ref' keyword. Is there a way in which the keyword is not needed or a better way of doing this
public static void ReadFile()
{
for(int i=0; i<5; i++)
{
if(this)
{
SetStatus(Program.systemAbortedHamiltons[i], i);
}
if(this)
{
SetStatus(Program.runningHamiltons[i], i);
}
}
}
public static void SetStatus(ref bool status, int i)
{
Console.WriteLine("SetStatus");
Program.systemAbortedHamiltons[i] = false;
Program.runningHamiltons[i] = false;
Program.userAbortedHamiltons[i] = false;
Program.methodEndHamiltons[i] = false;
status = true;
}
Hope this makes sense, any suggestions are greatly appreciated.
Classes in c# are Reference type and you can create an class like this
public class CheckStatus
{
public bool Status { get; set; }
}
then pass the an instance of class to method like this
public static void SetStatus(CheckStatus status,int i)
{
Console.WriteLine("SetStatus");
Program.systemAbortedHamiltons[i] = false;
Program.runningHamiltons[i] = false;
Program.userAbortedHamiltons[i] = false;
Program.methodEndHamiltons[i] = false;
status.Status = true;
}
and
public static void ReadFile()
{
CheckStatus status = new CheckStatus();
if(this)
{
status.Status = Program.systemAbortedHamiltons[i];
SetStatus(status, i);
Program.systemAbortedHamiltons[i] = status.Status;
}
if(this)
{
status.Status = Program.runningHamiltons[i];
SetStatus(status, i);
Program.runningHamiltons[i] = status.Status;
}
}
What you can do is pass the list itself as such: (assuming they are List<bool> but if not, just replace that with actual collection type)
public static void ReadFile()
{
if(/* condition 1 */)
{
SetStatus(Program.systemAbortedHamiltons, i);
}
if(/* condition 2 */)
{
SetStatus(Program.runningHamiltons, i);
}
}
public static void SetStatus(List<bool> statuses, int i)
{
Console.WriteLine("SetStatus");
Program.systemAbortedHamiltons[i] = false;
Program.runningHamiltons[i] = false;
Program.userAbortedHamiltons[i] = false;
Program.methodEndHamiltons[i] = false;
statuses[i] = true;
}
Below is a quick test to see if it works:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<bool> myList = new List<bool>
{
true, true, true
};
// Outputs "True"
Console.WriteLine(myList[0]);
SetFalse(myList, 0);
// Outputs "False"
Console.WriteLine(myList[0]);
}
static void SetFalse(List<bool> l, int i)
{
l[i] = false;
}
}
Outputs:
True
False
I am very new to C#, and trying to make a program that counts an array, and I'm having trouble using methods/properties on the array (Reset, PrintCounters, Increment). the problems occur from the for loops and below. Thanks in advance if anyone is able to help.
using System;
namespace CounterTest
{
public class MainClass
{
private static void PrintCounters(Counter[] counters)
{
foreach (Counter c in counters)
{
string name = "";
int value = 0;
Console.WriteLine("{0} is {1}", name, value);
}
}
public static void Main(string[] args)
{
Counter[] myCounters = new Counter[3];
myCounters[0] = new Counter("Counter 1");
myCounters[1] = new Counter("Counter 2");
myCounters[2] = myCounters[0];
for (int i = 0; i < 4; i++)
{
Counter.Increment(myCounters[0]);
}
for (int i = 0; i < 9; i++)
{
Counter.Increment(myCounters[1]);
}
Counter.PrintCounters(myCounters);
Counter.Reset(myCounters[2]);
Counter.PrintCounters(myCounters);
}
}
}
Counter class:
using System;
using System.Collections.Generic;
using System.Text;
namespace CounterTest
{
public class Counter
{
private int _count;
private string _name;
public Counter(string name)
{
_name = name;
_count = 0;
}
public void Increment()
{
_count++;
}
public void Reset()
{
_count = 0;
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int Value
{
get
{
return _count;
}
set
{
_count = value;
}
}
}
}
The methods you call are not static methods, so they are called like:
for (int i = 0; i < 4; i++)
{
myCounters[0].Increment();
}
for (int i = 0; i < 9; i++)
{
myCounters[1].Increment();
}
MainClass.PrintCounters(myCounters); //this is static
myCounters[2].Reset();
MainClass.PrintCounters(myCounters);
Counter is a type, not an instance, that's why Counter.Increment is an incorrect call (Increment is not a static method).
// Given intance of Counter - myCounters[1] call Increment() method on it
myCounters[1].Increment();
instead of
// Call static method of Counter class - Counter.Increment on instance of Counter
Counter.Increment(myCounters[1]);
etc. It can be something like this:
public static void Main(string[] args)
{
Counter[] myCounters = new Counter[3]
myCounters[0] = new Counter("Counter 1");
myCounters[1] = new Counter("Counter 2");
myCounters[2] = myCounters[0];
for (int i = 0; i < 4; i++)
{
// call Increment on myCounters[0] instance
myCounters[0].Increment();
}
for (int i = 0; i < 9; i++)
{
// call Increment on myCounters[1] instance
myCounters[1].Increment();
}
// PrintCounters method call
PrintCounters(myCounters);
// call Reset on myCounters[2] instance
myCounters[2].Reset();
// PrintCounters method call
PrintCounters(myCounters);
}
You are calling Counter.Increment and then providing a Counter as a parameter. This piece of code assumes Counter is a static class with static methods, which is not the case.
In your for loops, you should be using the code like this:
for (int i = 0; i < 4; i++)
{
myCounters[0].Increment();
}
You use Counter.Increment(myCounters[0]) like Increment was an extention method on Counter.
public static class ExtentionCounter
{
public static void Increment(this Counter cnt)
{
cnt.Value++;
}
}
When with your current definition you should use :
myCounters[0].Increment();
here is the solution for your code. Just compare with yours but see the changes are with ** .
On the PrintCounters since your looping trough the Counters as c you need to call the counter name and the valu with **c.Name and c.Value
using System;
using Test;
namespace teste
{
static class MainClass{
public static void PrintCounters(Counter[] counters)
{
foreach (Counter c in counters)
{
**string name = c.Name;**
**int value = c.Value;**
Console.WriteLine("{0} is {1}", name, value);
}
}
}
class Program
{
static void Main(string[] args)
{
Counter[] myCounters = new Counter[3];
myCounters[0] = new Counter("Counter 1");
myCounters[1] = new Counter("Counter 2");
myCounters[2] = myCounters[0];
for (int i = 0; i < 4; i++) {
**myCounters[0].Increment();**
}
for (int i = 0; i < 9; i++) {
**myCounters[1].Increment();**
}
**MainClass.PrintCounters(myCounters);**
**myCounters[2].Reset();**
**MainClass.PrintCounters(myCounters);**
}
}
}
Also since the myCounters is an instance of Counters you need to call the method of the instance like this:
myCounters[0].Increment()
Same for the other methods as Reset.
To call a static method you dont need to instantiate but in your case you need to do reference to the class to use the method PrintCounters like this:
MainClass.PrintCounters(myCounters);
Also use the keyword this.something to change instance variables.
using System;
using System.Collections.Generic;
using System.Text;
namespace Test
{
public class Counter
{
private int _count;
private string _name;
public Counter(string name)
{
**this._name = name;**
**this._count = 0;**
}
public void Increment()
{
**this._count++;**
}
public void Reset()
{
**this._count = 0;**
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int Value
{
get
{
return _count;
}
set
{
_count = value;
}
}
}
}
i hope it helps
copy paste the following code in new C# console app.
class Program
{
static void Main(string[] args)
{
var enumerator = new QueuedEnumerator<long>();
var listenerWaitHandle = Listener(enumerator);
Publisher(enumerator);
listenerWaitHandle.WaitOne();
}
private static AutoResetEvent Listener(IEnumerator<long> items)
{
var #event = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem((o) =>
{
while (items.MoveNext())
{
Console.WriteLine("Received : " + items.Current);
Thread.Sleep(2 * 1000);
}
(o as AutoResetEvent).Set();
}, #event);
return #event;
}
private static void Publisher(QueuedEnumerator<long> enumerator)
{
for (int i = 0; i < 10; i++)
{
enumerator.Set(i);
Console.WriteLine("Sended : " + i);
Thread.Sleep(1 * 1000);
}
enumerator.Finish();
}
class QueuedEnumerator<T> : IEnumerator<T>
{
private Queue _internal = Queue.Synchronized(new Queue());
private T _current;
private bool _finished;
private AutoResetEvent _setted = new AutoResetEvent(false);
public void Finish()
{
_finished = true;
_setted.Set();
}
public void Set(T item)
{
if (_internal.Count > 3)
{
Console.WriteLine("I'm full, give the listener some slack !");
Thread.Sleep(3 * 1000);
Set(item);
}
else
{
_internal.Enqueue(item);
_setted.Set();
}
}
public T Current
{
get { return _current; }
}
public void Dispose()
{
}
object System.Collections.IEnumerator.Current
{
get { return _current; }
}
public bool MoveNext()
{
if (_finished && _internal.Count == 0)
return false;
else if (_internal.Count > 0)
{
_current = (T)_internal.Dequeue();
return true;
}
else
{
_setted.WaitOne();
return MoveNext();
}
}
public void Reset()
{
}
}
}
2 threads (A,B)
A thread can provide one instance at a time and calls the Set method
B thread wants to receive a sequence of instances (provided by thread A)
So literally transforming an Add(item), Add(item), .. to a IEnumerable between different threads
Other solutions also welcome of course!
Sure - this code might not be the best way to do it, but here was my initial stab at it:
Subject<Item> toAddObservable;
ListObservable<Item> buffer;
void Init()
{
// Subjects are an IObservable we can trigger by-hand, they're the
// mutable variables of Rx
toAddObservable = new Subject(Scheduler.TaskPool);
// ListObservable will hold all our items until someone asks for them
// It will yield exactly *one* item, but only when toAddObservable
// is completed.
buffer = new ListObservable<Item>(toAddObservable);
}
void Add(Item to_add)
{
lock (this) {
// Subjects themselves are thread-safe, but we still need the lock
// to protect against the reset in FetchResults
ToAddOnAnotherThread.OnNext(to_add);
}
}
IEnumerable<Item> FetchResults()
{
IEnumerable<Item> ret = null;
buffer.Subscribe(x => ret = x);
lock (this) {
toAddObservable.OnCompleted();
Init(); // Recreate everything
}
return ret;
}
I have this sample code for async operations (copied from the interwebs)
public class LongRunningTask
{
public LongRunningTask()
{
//do nowt
}
public int FetchInt()
{
Thread.Sleep(2000);
return 5;
}
}
public delegate TOutput SomeMethod<TOutput>();
public class GoodPerformance
{
public void BeginFetchInt()
{
LongRunningTask lr = new LongRunningTask();
SomeMethod<int> method = new SomeMethod<int>(lr.FetchInt);
// method is state object used to transfer result
//of long running operation
method.BeginInvoke(EndFetchInt, method);
}
public void EndFetchInt(IAsyncResult result)
{
SomeMethod<int> method = result.AsyncState as SomeMethod<int>;
Value = method.EndInvoke(result);
}
public int Value { get; set; }
}
Other async approaches I tried required the aysnc page attribute, they also seemed to cancel if other page elements where actioned on (a button clicked), this approach just seemed to work.
I’d like to add a cancel ability and exception handling for the longRunningTask class, but don’t erm, really know how.
In example:
public class ValueEventArgs : EventArgs
{
public int Value { get;set;}
}
public class ExceptionEventArgs : EventArgs
{
public Exception Exception { get;set;}
}
public class LongRunningTask
{
private bool canceled = false;
public event EventHandler<ValueEventArgs> Completed = delegate {}
public event EventHandler<ExceptionEventArgs> GotError = delegate {}
public void Cancel()
{
canceled = true;
}
public void FetchInt()
{
try
{
int result = 0;
for (int i = 0; i < 1000; i++)
{
if (canceled)
return;
result++;
}
Completed(this, new ValueEventArgs {Value = result});
}
catch(Exception exc)
{
GotError(this, new ExceptionEventArgs { Exception = exc });
}
}
public void BeginFetchInt()
{
ThreadPool.QueueUserWorkItem(i => FetchInt());
}
}
And somewhere:
LongRunningTask task = new LongRunningTask();
task.Completed +=new EventHandler<ValueEventArgs>(task_Completed);
task.GotError +=new EventHandler<ExceptionEventArgs>(task_GorError);
task.BeginFetchInt();
//in any moment until it calculates you may call:
task.Cancel();