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.
Related
I wrote the following EXE File in C#:
namespace Service
{
class Program
{
[DllImport("user32.dll")]
public static extern int GetAsyncKeyState(Int32 i);
static void Main(string[] args)
{
StartLogging();
}
static void StartLogging()
{
while (true)
{
//sleeping for while, this will reduce load on cpu
Thread.Sleep(10);
for (Int32 i = 0; i < 255; i++)
{
int keyState = GetAsyncKeyState(i);
if (keyState == 1 || keyState == -32767)
{
using (StreamWriter outputFile = new StreamWriter("C:\\Output.txt", true))
{
outputFile.WriteLine((Keys)i);
}
break;
}
}
}
}
}
}
This program captures every keyboard event, no matter in which program. It works fine.
Then i tried to put this into a Windows Service and it doesn't work.
The following code is my Service:
namespace Dienst
{
public class Service : ServiceBase
{
[DllImport("user32.dll")]
public static extern int GetAsyncKeyState(Int32 i);
static void StartLogging()
{
while (true)
{
//sleeping for while, this will reduce load on cpu
Thread.Sleep(10);
for (Int32 i = 0; i < 255; i++)
{
int keyState = GetAsyncKeyState(i);
if (keyState == 1 || keyState == -32767)
{
using (StreamWriter outputFile = new StreamWriter("C:\\TestNeu.txt", true))
{
outputFile.WriteLine((Keys)i);
}
break;
}
}
}
}
static void Main()
{
Service.Run(new Service());
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
StartLogging();
}
protected override void OnContinue()
{
base.OnContinue();
}
protected override void OnStop()
{
base.OnStop();
}
}
[RunInstaller(true)]
public class Installation : Installer
{
private ServiceInstaller service;
private ServiceProcessInstaller process;
public Installation()
{
service = new ServiceInstaller();
process = new ServiceProcessInstaller();
service.ServiceName = "Service1";
service.DisplayName = "Service1";
service.Description = "WindowsService";
process.Account = ServiceAccount.LocalSystem;
Installers.Add(process);
Installers.Add(service);
}
}
}
The result from GetAsyncKeyState(i) is always 0.
Can anyone help me? I don't know, because this code as Service doesn't work.
And no, I don't want write a keylogger, only if someone think this.
I'm currently running into a problem with multithreading and accessing a static list. A static list holds all items with several properties. The items are identified with a Guid. A main work thread changes some properties for any item in the static list. The child threads all have their own Guid, with this Guid they read their own item in the static list. And after a specific event they remove their assigned element from the static list.
To get to the source I have broken down my code to the essential methods and classes. The work thread has the following simplified code
public void RunWork()
{
Random random = new Random();
Int32 index = -1;
while (!Kill)
{
Thread.Sleep(1);
if (MainWindow.Clients != null)
{
index = random.Next(0, MainWindow.Clients.Count);
MainWindow.Clients[index].State = MainWindow.RandomString(9);
}
}
}
Each child thread has the following simplified code
public void RunChild()
{
Random random = new Random();
while (!Kill)
{
Thread.Sleep(100);
if (MainWindow.Clients.Any(x => x.Id == Id))
{
this.State = MainWindow.Clients.First(x => x.Id == Id).State;
}
Thread.Sleep(random.Next(50));
if (random.Next(100) % 90 == 0)
{
Kill = true;
MainWindow.Clients.RemoveAll(x => x.Id == Id);
}
}
}
If a child removes itself from the MainWindow.Clients list the work thread throws a exception, that the index it is trying to access does not exist.
I have added lock statments around every access of MainWindow.Clients but this does not prevent the work thread from accessing a deleted item. I have also tried Monitor.Enter(MainWindow.Clients) and Monitor.Exit(MainWindow.Clients) but with the same result as with lock.
The static list MainWindow.Clients is created before any thread runs and never gets recreated or disposed.
If the lock statement is set around this block of code in the RunWork() method
lock (MainWindow.Clients)
{
Thread.Sleep(1);
if (MainWindow.Clients != null)
{
index = random.Next(0, MainWindow.Clients.Count);
MainWindow.Clients[index].State = MainWindow.RandomString(9);
}
}
Why does it not block the child threads from changing the list between the lines
where the random index is set and the list gets accessed?
Update 1:
The following code still throws a IndexOutOfRangeException at MainWindow.Clients[index].State = MainWindow.RandomString(9);:
public void RunWork()
{
Random random = new Random();
Int32 index = -1;
while (!Kill)
{
Thread.Sleep(1);
if (MainWindow.Clients != null)
{
lock (MainWindow.Clients)
{
index = random.Next(0, MainWindow.Clients.Count);
MainWindow.Clients[index].State = MainWindow.RandomString(9);
}
}
}
}
public void RunChild()
{
Random random = new Random();
while (!Kill)
{
Thread.Sleep(100);
if (MainWindow.Clients.Any(x => x.Id == Id))
{
this.State = MainWindow.Clients.First(x => x.Id == Id).State;
}
Thread.Sleep(random.Next(50));
if (random.Next(100) % 90 == 0)
{
Kill = true;
lock (MainWindow.Clients)
{
MainWindow.Clients.RemoveAll(x => x.Id == Id);
}
}
}
}
Update 2: Here is the complete code for the quick sample application
Update 3: I have edited my code and wrapped all accesses of MainWindow.Clients with lock statements. But still the threads access the variable while it is locked:
I'm not sure what exactly you are trying to achieve, but I've written something that might help you find the correct solution. Sorry for the lack of correctness - tight schedule ;-)
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace ConcurrentCollectionTest
{
internal class Client
{
public string State
{
get; set;
}
public string Name
{
get;
internal set;
}
}
internal class MainWindow
{
private ConcurrentDictionary<int, Client> _dict = new ConcurrentDictionary<int, Client>();
public IDictionary<int, Client> Clients
{
get
{
return _dict;
}
}
}
internal class Program
{
private static bool killAll = false;
private static MainWindow mainWindow = new MainWindow();
private static int id = -100;
private static string state = "Initial";
private static Random random = new Random();
private static object lockObject = new object();
internal static string RandomString(int v)
{
int k = random.Next(0, v);
return k.ToString();
}
public static void RunChild()
{
Debug.WriteLine($"child running {Thread.CurrentThread.Name}");
bool killThis = false;
while (!killThis && !killAll)
{
Thread.Sleep(100);
Client client = null;
if (mainWindow.Clients.TryGetValue(id, out client))
{
state = client.State;
}
Thread.Sleep(random.Next(50));
if (random.Next(100) % 90 == 0)
{
Debug.WriteLine($"killing {Thread.CurrentThread.Name}");
killThis = true;
lock (lockObject)
{
mainWindow.Clients.Remove(id);
}
}
}
}
public static void RunWork()
{
Console.WriteLine("RunWork");
Random random = new Random();
Int32 index = -1;
while (!killAll)
{
if (!mainWindow.Clients.Any())
{
killAll = true;
break;
}
Thread.Sleep(100);
// edit: still need lock here as count can change in between
Client client = null;
lock (lockObject)
{
index = random.Next(0, mainWindow.Clients.Count);
client = mainWindow.Clients[index];
}
Debug.WriteLine($"Changing {client.Name}");
client.State = RandomString(9);
}
Console.WriteLine("Worker killed");
}
private static void Main(string[] args)
{
Console.WriteLine("Starting. Enter id or kill");
for (int i = 0; i < 100; i++)
{
mainWindow.Clients.Add(i, new Client
{
Name = $"Client {i:000}",
State = "Unknown"
});
}
var worker = new Thread(RunWork);
worker.Start();
var threadList = new List<Thread>();
threadList.Add(worker);
for (int i = 0; i < 10; i++)
{
var thread = new Thread(RunChild)
{
Name = $"Child {i:00}"
};
threadList.Add(thread);
thread.Start();
}
while (!killAll)
{
var str = Console.ReadLine();
if (str.Equals("kill", StringComparison.InvariantCultureIgnoreCase))
{
killAll = true;
break;
}
int enteredId = -1;
if (int.TryParse(str, out enteredId))
{
id = enteredId;
}
}
foreach (var thread in threadList)
{
thread.Join();
}
Console.WriteLine("all dead");
}
}
}
I am new to multi-thread programming in C#. My problem is that I don't know how to wait for a method that is being run on another thread to finish, before it can continue to the next line. For example, something like this
public class A
{
int i;
public A()
{
i = 0;
}
protected void RunLoop()
{
while(i < 100)
{
i++;
}
}
public void Start()
{
TimerResolution.TimeBeginPeriod(1);
runThread = new Thread(new ThreadStart(RunLoop));
running = true;
runThread.Start();
}
}
public class B
{
A classAInstance = new A();
A.Start();
Console.Writeline(i);
}
Right now, it prints 0 on the console, which is not what I want (i.e. i = 100).
What is the best way to do this? BTW, I don't have access to the runThread that is created in class A
Thanks.
EDIT:
It was a bit difficult to solve this problem without modifying a lot codes. Therefore, we ended up with adding a condition in the public void Start() with which it can decide whether to run the RunLoop in a separate thread or not. The condition was defined using an Enum field.
public void Start()
{
TimerResolution.TimeBeginPeriod(1);
running = true;
if (runningMode == RunningMode.Asynchronous)
{
runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
else
{
RunLoop();
}
}
And
public enum RunningMode { Asynchronous, Synchronous };
Thanks everyone for help.
The preferred method is to use the Task Parallel Library (TPL) and use Task with await.
If you must use Threads, then use a ManualResetEvent or ManualResetEventSlim to signal the end of a method.
void Main()
{
var a = new A();
a.Start();
a.FinishedEvent.WaitOne();
Console.WriteLine(a.Index);
}
// Define other methods and classes here
public class A
{
ManualResetEvent mre = new ManualResetEvent(false);
int i;
public EventWaitHandle FinishedEvent
{
get { return mre; }
}
public int Index
{
get { return i; }
}
public A()
{
i = 0;
}
protected void RunLoop()
{
while (i < 1000)
{
i++;
}
mre.Set();
}
public void Start()
{
var runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
}
Your life would be so much better with tasks.
Your code could be this simple:
var task = Task.Factory.StartNew(() =>
{
var i = 0;
while (i < 100)
{
i++;
}
return i;
});
Console.WriteLine(task.Result);
I like use Monitor.Wait() and Monitor.Pulse() in conjunction with "lock" operator. It works, but you must be careful, when you use this technique.
I'm added some changes to your code to demonstrate it. Code below are prints i== 100, as you want.
public class A
{
int i;
public object SyncObject
{ get; private set; }
public A()
{
SyncObject = new object();
i = 0;
}
protected void RunLoop()
{
while (i < 100)
{
i++;
}
lock (SyncObject)
{
Monitor.Pulse(SyncObject);
}
}
public void Start()
{
var runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
public void PrintI()
{
Console.WriteLine("I == " + i);
}
}
public class B
{
public static void Run()
{
A classAInstance = new A();
lock (classAInstance.SyncObject)
{
classAInstance.Start();
Monitor.Wait(classAInstance.SyncObject);
}
classAInstance.PrintI();
}
}
I'm trying to create a Sheduler (for fun) but it fails. Strange is that when i'm debugging in step-over style, my programm works fine, but when i'm removing all breakpoints it freezes after printing last value. So question: why does it freezes? Second: i'm using Thread.Resume and Thread.Suspend, but they are marked as obsolete. How can i avoid it?
Code is below:
using System;
using System.Collections.Generic;
using System.Threading;
namespace ConsoleApplication143
{
internal class Program
{
private static void Main()
{
var rrs = new RobinRoundSheduler(2, () =>
{
for (int i = 0; i < 2; i++)
{
Console.WriteLine("{0} {1}", i,
Thread.CurrentThread.ManagedThreadId);
}
}) {TimeForTask = new TimeSpan(1)};
rrs.Start();
Console.ReadKey();
}
}
internal class RobinRoundSheduler
{
private readonly LinkedList<Thread> _threads;
public TimeSpan TimeForTask { get; set; }
public RobinRoundSheduler(int taskCount, ThreadStart start)
{
TimeForTask = TimeSpan.FromSeconds(1);
_threads = new LinkedList<Thread>();
for (int i = 0; i < taskCount; i++)
{
_threads.AddLast(new Thread(start));
}
}
public void Start()
{
while (_threads.Count > 0)
{
var list = new List<Thread>();
foreach (var thread in _threads)
{
lock (thread)
{
if (thread.ThreadState == ThreadState.Unstarted)
thread.Start();
else
thread.Resume();
}
thread.Join(TimeForTask);
lock (thread)
{
if (thread.ThreadState == ThreadState.Stopped || thread.ThreadState == ThreadState.Aborted)
list.Add(thread);
else
{
thread.Suspend();
}
}
}
list.ForEach(thread => _threads.Remove(thread));
}
}
}
}
it seems having a deadlock problem due to Thread.Suspend() method but i dunno another alternative to suspend a thread withoud adding checks for ManualResetEvents in calling methods. But i want to call method knows nothing about multithreading.
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;
}