My unity project is a procedural environment on Android and creates terrains and stuff at runtime. The overall workflow I use is to calculate anything non-unity in a worker thread and when the data is calculated, I call Unity API within the main thread.
The problem is that sometimes (like every 200 frames) the worker thread affects the main thread's performance. That could show itself with a nasty spike in rendering time.
So what to do with multithreading in unity?
EDIT: The android device is quad core.
EDIT 2: I believe what Sam said in the comments is exactly what's happening.
I wonder if you can determine what core the code is running on, or if
you can set the thread affinity? I found some links where people
described similar situations: here and here. Sounds like
it's picking the same core as the main thread occasionally.
So maybe this is not about unity but every real time interactive multithreaded application. I believe it is possible to set thread affinity on some versions of some platforms but that destroys the cross platform status of the system.
PS: Not exactly the main issue but to make the question more concrete, I will include the worker thread implementation. It is a modified version of the worker thread implementation suggested in this post. The modified version is like this:
public static class JobScheduler
{
private static Queue<Job> Jobs = new Queue<Job>();
private static volatile bool isBusy;
private static ManualResetEvent _workAvailable = new ManualResetEvent(false);
static JobScheduler()
{
var backgroundWorkThread = new Thread(BackgroundThread)
{
IsBackground = true,
Priority = ThreadPriority.Lowest,
Name = "BasicBackgroundWorker Thread"
};
backgroundWorkThread.Start();
}
private static void BackgroundThread()
{
int jobCnt;
while (true)
{
Job? workItem=null;
lock (Jobs)
{
jobCnt = Jobs.Count;
if (jobCnt != 0 && !isBusy)
{
workItem = Jobs.Dequeue();
}
}
if (workItem!=null)
{
isBusy = true;
workItem.Value.callback(workItem.Value.param);
}
else
{
_workAvailable.WaitOne();
_workAvailable.Reset();
}
}
}
public static void AddJob(Job Job)
{
lock (Jobs)
{
Jobs.Enqueue(Job);
}
_workAvailable.Set();
}
public static void JobDone()
{
isBusy = false;
_workAvailable.Set();
}
}
And the Job struct:
public struct Job
{
public object param;
public WaitCallback callback;
public Job(WaitCallback callBackP
, object parameter)
{
callback = callBackP;
param = parameter;
}
}
Whenever needed I call JobScheduler.AddJob to enqueue a job and call JobScheduler.JobDone after the job is done to allow the next job to run.
Also the ThreadPool is not an option since it produces unnecessary garbage and is not very flexible to use.
Related
I have a C# Windows IoT Background application I have created. That application has multiple threads in the ThreadPool that run indefinitely.
These threads need to be able to read/write to global variables in the main thread, but I am not sure how to accomplish this. Here is an example of what I am trying to do:
// main task
public sealed class StartupTask : IBackgroundTask
{
private static BackgroundTaskDeferral _Deferral = null;
private static MyThreadClass1 thread1 = null;
private static MyThreadClass2 thread2 = null;
private static MyThreadClass3 thread3 = null;
List<Object> MyDevices = null;
public async void Run(IBackgroundTaskInstance taskInstance)
{
_Deferral = taskInstance.GetDeferral();
MyDevices = GetDeviceList();
thread1 = new MyThreadClass1();
await ThreadPool.RunAsync(workItem =>
{
thread1.Start();
});
thread2 = new MyThreadClass2();
await ThreadPool.RunAsync(workItem =>
{
thread2.Start();
});
thread3 = new MyThreadClass3();
await ThreadPool.RunAsync(workItem =>
{
thread3.Start();
});
}
}
internal class MyThreadClass1
{
public async void Start()
{ }
}
internal class MyThreadClass2
{
public async void Start()
{ }
}
internal class MyThreadClass3
{
public async void Start()
{ }
}
In any of the three threads that are running, I need to be able to read and write to List<Object> MyDevices.
The threads all have different functions, but they all interact with "MyDevices", so if one thread makes a change to that list, the other threads need to know about the change right away.
What is the best way to go about doing this?
Thanks!
These threads need to be able to read/write to global variables in the main thread
The easiest way to deal with this requirement is to remove it. Is it possible to code the solution so that each thread owns a device? Or is it possible to rethink the thread's responsibilities so that they communicate by message passing instead of updating shared data? Usually these alternative approaches result in much cleaner and less buggy code. But not always.
You will need locks to protect shared data. The easiest way to do this is with the lock statement, e.g.:
object _mutex = new object();
List<Object> MyDevices = null;
...
var device = ...;
lock (_mutex)
{
MyDevices.Add(device);
}
Generally, you want to minimize the code in the lock statement. Also, you may want to have one lock for the List<Object> and a separate lock for each item in the list, depending on how your thread use those devices.
One thing you might want to consider using is an ObservableCollection. This class implements the INotifyPropertyChanged interface, which notifies any listeners of changes to the underlying collection.
Next, you'll want to implement an event handler for PropertyChanged in your Thread classes like so (I recommend making either an interface or base class that handles this since you appear to be using different classes for each Thread):
public sealed class MyThreadBase
{
private ObservableCollection<object> MyDevices;
public MyThreadBase(ObservableCollection<object> deviceList)
{
MyDevices = deviceList;
MyDevices.PropertyChanged += MyDevices_PropertyChanged; // Register listener
}
private void MyDevices_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
lock (MyDevices)
{
// Do something with the data...
}
}
}
The lock statement is used so that the thread is blocked when another thread is reading or writing to MyDevices. This is typically important in synchronization and is known as the readers-writers problem. I'd suggest reading up on that and possible solutions as well.
If you intend, however, for each thread to iterate over the devices and do something with each one, then you will run into issues, as iterating over a changing collection is not a good idea (and when using a foreach loop, will actually throw an exception), so keep that in mind too.
other threads need to know about the change right away
If you want low latency notifications, threads must spend the majority of time sleeping on something. E.g. executing Dispatcher.Run() that will sleep waiting for messages/tasks to process.
If that’s your case, you can use ObservableCollection instead of List, and write CollectionChanged handler that forwards notifications for your 3 threads. Or if that’s what you want, forward notifications to 2 other threads, excluding the current one, if you won’t want the thread that initiated the change to process changed event.
I'm not sure if the Dispatcher class is available on Windows IoT platform. Definitely not the case for .NET core. Even if not, high-level building blocks to create one are available. Here’s an example implementation that also implements synchronization context, very simple because relies on high-level ConcurrentQueue and BlockingCollection generic classes.
using kvp = KeyValuePair<SendOrPostCallback, object>;
enum eShutdownReason : byte
{
Completed,
Failed,
Unexpected,
}
class Dispatcher : IDisposable
{
const int maxQueueLength = 100;
readonly ConcurrentQueue<kvp> m_queue;
readonly BlockingCollection<kvp> m_block;
public Dispatcher()
{
m_queue = new ConcurrentQueue<kvp>();
m_block = new BlockingCollection<kvp>( m_queue, maxQueueLength );
createdThreadId = Thread.CurrentThread.ManagedThreadId;
prevContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext( new SyncContext( this ) );
}
readonly SynchronizationContext prevContext;
readonly int createdThreadId;
class SyncContext : SynchronizationContext
{
readonly Dispatcher dispatcher;
public SyncContext( Dispatcher dispatcher )
{
this.dispatcher = dispatcher;
}
// https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
public override void Post( SendOrPostCallback cb, object state )
{
dispatcher.Post( cb, state );
}
}
/// <summary>Run the dispatcher. Must be called on the same thread that constructed the object.</summary>
public eShutdownReason Run()
{
Debug.Assert( Thread.CurrentThread.ManagedThreadId == createdThreadId );
while( true )
{
kvp h;
try
{
h = m_block.Take();
}
catch( Exception ex )
{
ex.logError( "Dispatcher crashed" );
return eShutdownReason.Unexpected;
}
if( null == h.Key )
return (eShutdownReason)h.Value;
try
{
h.Key( h.Value );
}
catch( Exception ex )
{
ex.logError( "Exception in Dispatcher.Run" );
}
}
}
/// <summary>Signal dispatcher to shut down. Can be called from any thread.</summary>
public void Stop( eShutdownReason why )
{
Logger.Info( "Shutting down, because {0}", why );
Post( null, why );
}
/// <summary>Post a callback to the queue. Can be called from any thread.</summary>
public void Post( SendOrPostCallback cb, object state = null )
{
if( !m_block.TryAdd( new kvp( cb, state ) ) )
throw new ApplicationException( "Unable to post a callback to the dispatcher: the dispatcher queue is full" );
}
void IDisposable.Dispose()
{
Debug.Assert( Thread.CurrentThread.ManagedThreadId == createdThreadId );
SynchronizationContext.SetSynchronizationContext( prevContext );
}
}
Regardless on whether you’ll use built-in Dispatcher or my custom one, all threads must call it’s Run method, then use asynchronous posted tasks, or async methods, to run code within the dispatcher.
I have been given an application that boils down to being a producer-consumer pattern. Several threads are doing some work and updating a single data set so that several more threads can consume that data and do their own work with it. At the moment, it's not terribly complex, all the consuming threads wait on the data set until one of the producers calls a pulseall.
There is now a desire to have one of the consumer threads consume from two different data sets anytime either of the sets changes. The teams desire to keep refactoring to a minimum and my limited experience with threading has given me some issues finding a clean solution.
The quick and dirty solution was to do the waiting and pulsing on a separate object and have the consumer threads check for changes in their data set before continuing. There does not seem to be a way for one thread to wait on two objects, without replacing the generic threads with a more robust threading tool (thread pools, task, etc) unless I'm failing to google the right thing.
If you are willing to do a little refactoring I would recommend switching from Monitor to one of the EventWaitHandle derived classes.
Depending on the behavior you want you may want AutoResetEvent, that will more closely act like a Monitor.Entier(obj)/Monitor.Exit(obj)
private readonly object _lockobj = new Object();
public void LockResource()
{
Monitor.Enter(_lockobj);
}
public void FreeResource()
{
Monitor.Exit(_lockobj);
}
//Which is the same as
private readonly AutoResetEvent _lockobj = new AutoResetEvent(true);
public void LockResource()
{
_lockobj.WaitOne();
}
public void FreeResource()
{
_lockobj.Set();
}
or you may want ManualResetEvent will more closely act like Monitor.Wait(obj)/Monitor.PulseAll(obj)
private readonly object _lockobj = new Object();
public void LockResource()
{
Monitor.Enter(_lockobj);
}
public bool WaitForResource()
{
//requires to be inside of a lock.
//returns true if it is the lock holder.
return Monitor.Wait(_lockobj);
}
public void SignalAll()
{
Monitor.PulseAll(_lockobj);
}
// Is very close to
private readonly ManualResetEvent _lockobj = new ManualResetEvent(true);
public bool LockResource()
{
//Returns true if it was able to perform the lock.
return _lockobj.Reset();
}
public void WaitForResource()
{
//Does not require to be in a lock.
//if the _lockobj is in the signaled state this call does not block.
_lockobj.WaitOne();
}
public void SignalAll()
{
_lockobj.Set();
}
1 event can wake up multiple threads, to handle multiple events by one thread you can do
ManualResetEvent resetEvent0 = ...
ManualResetEvent resetEvent1 = ...
public int WaitForEvent()
{
int i = WaitHandle.WaitAny(new WaitHandle[] {resetEvent0, resetEvent1});
return i;
}
and i will be the index of the reset event that had Set() called on it.
Consider the following abstract class:
public abstract class Worker {
protected bool shutdown;
protected Thread t;
/// <summary>
/// defines that we have an auto unpause scheduled
/// </summary>
private bool _unpauseScheduled;
/// <summary>
/// when paused; schedule an automatic unpause when we
/// reach this datetime
/// </summary>
private DateTime pauseUntil;
private bool _isStopped = true;
public bool IsStopped {
get {
return t.ThreadState == ThreadState.Stopped;
}
}
private bool _isPaused = false;
public bool IsPaused {
get {
return _isPaused;
}
}
private string stringRepresentation;
public Worker() {
t = new Thread(ThreadFunction);
stringRepresentation = "Thread id:" + t.ManagedThreadId;
t.Name = stringRepresentation;
}
public Worker(string name) {
t = new Thread(ThreadFunction);
stringRepresentation = name;
t.Name = stringRepresentation;
}
public void Start() {
OnBeforeThreadStart();
t.Start();
}
public void ScheduleStop() {
shutdown = true;
}
public void SchedulePause() {
OnPauseRequest();
_isPaused = true;
}
public void SchedulePause(int seconds) {
_unpauseScheduled = true;
pauseUntil = DateTime.Now.AddSeconds(seconds);
SchedulePause();
}
public void Unpause() {
_isPaused = false;
_unpauseScheduled = false;
}
public void ForceStop() {
t.Abort();
}
/// <summary>
/// The main thread loop.
/// </summary>
private void ThreadFunction() {
OnThreadStart();
while (!shutdown) {
OnBeforeLoop();
if (!IsPaused) {
if (!OnLoop()) {
break;
}
} else {
// check for auto-unpause;
if (_unpauseScheduled && pauseUntil < DateTime.Now) {
Unpause();
}
}
OnAfterLoop();
Thread.Sleep(1000);
}
OnShutdown();
}
public abstract void OnBeforeThreadStart();
public abstract void OnThreadStart();
public abstract void OnBeforeLoop();
public abstract bool OnLoop();
public abstract void OnAfterLoop();
public abstract void OnShutdown();
public abstract void OnPauseRequest();
public override string ToString() {
return stringRepresentation;
}
}
I use this class to create Threads that are designed to run for the lifetime of the application, but also with the ability to pause and stop the threads as needed.
I can't help but shake the feeling that my implementation is naive though. My use of Thread.Sleep() gives me pause. I am still learning the ins and outs of threads, and I am looking to see what others might do instead.
The Worker derived objects need to be able to do the following:
Run for the lifetime of the application (or as long as needed)
Be able to stop safely (finish what is was doing in OnLoop())
Be able to stop unsafely (disregard what is happening in OnLoop())
Be able to pause execution for a certain amount of time (or indefinitly)
Now, my implementation works, but that is not good enough for me. I want to use good practice, and I could use some review of this to help me with that.
I can't help but shake the feeling that my implementation is naive though. My use of Thread.Sleep() gives me pause. I am still learning the ins and outs of threads, and I am looking to see what others might do instead.
Your intuitions are good here; this is a naive approach, and any time you sleep a thread in production code you should think hard about whether you're making a mistake. You're paying for that worker; why are you paying for it to sleep?
The right way to put a thread to sleep until it is needed is not to sleep and poll in a loop. Use an appropriate wait handle instead; that's what wait handles are for.
But a better approach still would be to put an idle thread back into a pool of threads; if the work needs to be started up again in the future, schedule it onto a new worker thread. A thread that can sleep forever is a huge waste of resources; remember, a thread is a million bytes of memory by default. Would you allocate a bunch of million-byte arrays and then never use them?
You should study the design of the Task Parallel Library for additional inspiration. The insight of the TPL is that threads are workers, but what you care about is getting tasks completed. Your approach puts a thin layer on top of threads, but it does not get past the fact that threads are workers; managing workers is a pain. State your tasks, and let the TPL assign them to workers.
You might also examine the assumptions around the up-to-date-ness of your various flags. They have no locks and are not volatile, and therefore reads and writes can be moved forwards and backwards in time basically at the whim of the CPU.
You also have some non-threading bugs to think about. For example, suppose you decide to pause for thirty minutes, but at five minutes before clocks "spring forward" for daylight savings time. Do you pause for half an hour, or five minutes? Which do you actually intend?
I am working on some interesting concepts related to wrapping threads.
I have called it Fiber for now.
http://net7mma.codeplex.com/SourceControl/latest#Concepts/Classes/Threading/Threading.cs
Eric Lippert is is correct about paying a worker to sleep in some regard, if you imagine Eric Lippert is paid salary as opposed to via the hour then technically he is paid to sleep just as any other salaried employee.
How this relates to the concept at hand?
What about Priority? The CPU(s) that are executing your code are contending with their own pipelines for execution context as well as requests from the scheduler.
No one makes any mention of reducing the Priority which will reduce the amount of time given to execution of the context by the scheduler.
Chaining the Priority will thus increase the amount of cycles given to other context's and additionally will reduce the power consumption of your processor at the same time making your application run longer if it has a limited source of power (unless of course your using the excess heat to provide additional power to your system.)
I have class which implements an endless worker thread like this example, in my case representing a body. During runtime I will have between 0 and ~8 instances live at any time with instances constantly being created and destroyed.
Most of the time this class has a lifecycle of 30 seconds to 5 minutes but occasionally there may be a number of instances created and destroyed in a relatively short period of time. This is where I tend to run into performance issues given the low spec hardware this code is running on.
I would now like to rewrite the behavior so that I use a ThreadPool for my collection of running workers and I am struggling to find the correct way to structure the code.
Basically the code I have at the moment is something like
public class BodyCollection : IReadOnlyDictionary<ulong, TrackedBody>
{
public void Update()
{
if (createNew)
{
var body = new TrackedBody();
body.BeginTracking();
this.Add(1234, body);
}
if (remove)
{
TrackedBody body = this[1234];
body.StopTracking();
this.Remove(body);
}
}
}
public class TrackedBody
{
private readonly Thread _BiometricsThread;
private volatile bool _Continue = true;
public TrackedBody()
{
_BiometricsThread = new Thread(RunBiometricsThread);
}
public void BeginTracking()
{
_BiometricsThread.Start();
}
public void StopTracking()
{
_Continue = false;
}
private void RunBiometricsThread()
{
while(_Continue)
{
System.Threading.Thread.Sleep(1000);
}
}
}
So how do I re-write the above to utilize a ThreadPool correctly and so that I can cancel running threads on the ThreadPool as required? Do I use CancellationTokens or ManualResetEvents to control the threads?
I strongly believe you should be using more modern methods of asynchronous programming. We are going to use the Task Parallel Library here because it gives you the features you want for free:
Tracking completion
Cancellation
Thread pool
public class TrackedBody
{
public Task BeginTrackingAsync(CancellationToken cancellation)
{
return Task.Run(() => RunBiometricsThread(cancellation));
}
private void RunBiometricsThread(CancellationToken cancellation)
{
while(!cancellation.IsCancellationRequested)
{
Task.Delay(1000, cancellation);
}
}
}
Note that I have removed the async keyword. This was doing nothing on its own.
You can use the task to track the state of the ongoing work. You can use the cancellation token to stop all work.
I have a single thread VB.net service that checks a database for specific information. If the info does not exist, it needs to wait 15 minutes and try again. What is the best method to have the service wait during this 15 minute period? I considered a Do loop with threading.thread.sleep, but am always reading how that is bad to use, but I do not know an alternative. Any suggestions of a better method for this would be appreciated.
I guess you may, alternatively to Thread.Sleep:
1 - Make your application as SINGLE INSTANCE (see the Properties of your Solution).
2- Add an Schedule Event into Task Scheduler of the Windows to call your application on each 15 minutes.
3- Your program will be terminated normally and will be called from Windows (or manually by user).
4- Since Single-Event you won´t have many instances of the application running at the same time - just one. So, even if the Task Scheduler starts a new instance, you may be sure that just one instance will be running.
Using a BackgroundWorker and a ManualResetEvent I think you can do what you have in mind.
public class LibraryBackgroundTimer : BackgroundWorker
{
private ManualResetEvent intervalManualReset;
public int Interval { get; set; }
public LibraryBackgroundTimer()
{
this.WorkerSupportsCancellation = true;
this.Interval = 1000;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
while (!this.CancellationPending)
{
base.OnDoWork(e);
this.Sleep();
}
}
public void Start()
{
if (this.IsBusy)
return;
this.intervalManualReset = new ManualResetEvent(false);
this.RunWorkerAsync();
}
public void Stop()
{
this.CancelAsync();
this.WakeUp();
this.Dispose(true);
}
public void WakeUp()
{
if (this.intervalManualReset != null)
this.intervalManualReset.Set();
}
private void Sleep()
{
if (this.intervalManualReset != null)
{
this.intervalManualReset.Reset();
this.intervalManualReset.WaitOne(this.Interval);
}
}
}
using this class your timer can be stopped for a desired time and also it's capable of being waked up during the sleep time.
I hope this helps.