System.Random & bonus question on threading

So i’m doing stuff in a thread so I can’t use the unity.random class, but the system.random class doesn’t really take a ranged argument(NextDouble), it just returns 0-1.

what’s the best(performance-wise) way to get a float in a range where the minimun is greater than zero?
if we just wanna have 0-max sure it’s just (NextDouble*maxValue), but if I want a number from 1-10 for example, is the only way to go about it is to lerp from min to max by the random value? the docs says nothing about this.

also - bonus question, why do threads started using “ThreadPool.QueueUserWorkItem” don’t communicate errors to the console? (null reference and “can’t call this in a thread” type runtime errors)
if a thread is started using “new Thread(funcName).Start()” it logs errors fine.
and in both cases if I have a Debug.Log it gets to the console just fine

Your question is probably more involved than you let on, so I’ll tread carefully here :slight_smile:

Do you want integers or merely floats greater than zero?

In any event, making sure you get a minimum from a zero-based number you usually simply add the lower limit.

or, to go step by step

  • if you have lower and upper limit (lower, upper), we have a
  • range = upper - lower
  • and a random float floatRandom that goes from 0…1, that gives us a
  • rangedRandom = floatRandom * range and we than add the lower limit
  • returnRandom = rangedRandom + lower

Then again, I’m sure you already know all this so I’m not entirely sure what the real issue is…

1 Like

floats with a range from min to max, in my case right now it’s only positive and greater than zero.

How the bleep did that obvious solution not come to mind…

Not much of an issue, more like what’s the best practice here, if I didn’t have the thread pool question in there too I’d probably not even make this post.

thanks buddy.

Snippets like these brings back memories from my youth. That and
var rounded = (int) floatValue + 0.5f

Language APIs was very barebone back then :slight_smile:

1 Like

You did suggest lerp in the OP, and what csofranz posted is probably exactly how Mathf.Lerp is implemented.

1 Like

Note that the MS documentation on the Random class is very very verbose. The remarks section on the class is huge with tons of examples. There’s also one for getting a floating point number in a specific range.

2 Likes

Thank you all for the answers, but does anyone have any idea what’s going on with the ThreadPool?

Exceptions in a seperate thread are never catched by Unity since Unity is not responsible for those threads. Threads which throw an exception are silently terminated by the OS. If you want to catch exceptions on a seperate thread you have to use a try catch inside your thread code. You can use

void MyThread()
{
    try
    {
        //your thread code
    }
    catch(Exception e)
    {
        Debug.Log(e);
    }
}

That’s not true, try running this code:

public class Test : MonoBehaviour {

void Start(){

new Thread(ThreadedFunction).Start();
}

void ThreadedFunction(){

float val = UnityEngine.Random.value;
}

}

you should get a message in the console saying that UnityEngine.Random can only be called from the main thread and if you get a null reference it should spit it out to the console, if you start a thread with this function but use the ThreadPool you don’t get messages but it still stops the thread.

*I wrote this here so might have to fix 1 or 2 errors.

edit: forgot to mention i’m on unity 2019.4.12

edit2: could it be that you’re confusing it with starting a new process?

No, I’m not confusing this with new process ^^. Maybe this has changed but I actually doubt it. We have countless threads on this topic like this one .

Please note that what you caused in your thread is not an exception but an deliberately caused error by the Unity API as a result of their thread check.

Currently I don’t have a UnityEditor at hand, so I can not do any tests. However if you did one, try with an actual exception.

Forget the unity functions, 100% it throws a null reference exception and index out of bound exception(as i’m sure all the other exceptions), if it doesn’t at your end I would love to know and exchange a script or two with you.

If your thread has an unhandled exception, the OS will close your entire process. Most likely, Unity runs scripts in a sandbox and handles all exceptions in the same way, so that a game won’t crash completely when hitting an exception.

There are several differences between threads used by creating a new one vs dispatching to the ThreadPool, though, there are more similarities.

One of the differences is that created threads have a default state of “.IsBackground” == false, while ThreadPool threads have a state of “.IsBackground” == true. By default, all that does is determine which threads are allowed to keep a process alive, but could theoretically be used to determine which threads should have messages sent to Debug.Log.

I don’t know why these threads would be treated differently for what gets sent to Debug.Log, but it’s something that would be handled by the “unhandled exception handler” set by Unity.

1 Like

okay… cool, that’s one step closer and a thread to pull on (no pun intended, lol).
can we set the default state for the pooled threads? i’ll go check the docs.

So I tested this by setting the .background on not pooled thread, it sends stuff to the console just fine (tested with a simple null ref.)
But I have no idea how to control a thread that is pooled (can you even do that?) so I can’t test changing it on him, but if it didn’t matter here it’s probably something else.

but thank you for the information

Is this just a theoretical question, or are you trying to solve something pragmatic?
There may be alternatives to what you are trying to do.

1 Like

Well I’m using the thread pool in my game and if the thread crashes I wanna see the reason.
Currently I just commented the ThreadPool out and just create a new thread so I can get the logs if it crashes, I’m just gonna switch it when I build.

It would be preferable to just use the thread pool during development but also I wanna know what’s going on regardless of the problem, the more you know… you know? heh

Then you can take Bunny83’s advice and just wrap your code in a Pokemon Exception Handler.
You might be able to use a generic wrapping call like this …

public void Start()
{
  ThreadHelper.QueueUserWorkItem(MyFunctionToRunOnThread);
}

// ...

public static class ThreadHelper
{
  public static void QueueUserWorkItem(Action<object> threadPoolCallBack, object context = null)
  {
    ThreadPool.QueueUserWorkItem(() => Wrapper(threadPoolCallBack, context));
  }

  private static void Wrapper(Action<object> action, object context)
  {
    try
    {
      action(context);
    }
    catch (Exception e)
    {
      Debug.Log(e);
      throw;
    }
  }
}

An alternative I’ve seen suggested is to hook into the AppDomain’s UnhandledException handler.

public void Awake()
{
  // Make sure this is only called ONCE in your entire project
  AppDomain.Current.UnhandledException += Handler;
}

private void Handler(object sender, UnhandledExceptionEventArgs e)
{
  if (e.ExceptionObject is Exception ex)
    Debug.Log(ex);
}
1 Like

I don’t wanna wrap my code in a try catch.
Thanks for the heads up on the handler, I’ll look into that.