I have an assignment to make a thread safe logging class that writes to a file. Every ten frames I am supposed to push some information of my choice to the logging class from a separate script. I was wondering how to do that. Here is my code so far.
public class Threading
{
public bool Execute = true;
public Vector3 player;
public Vector3 WriteTime;
System.Collections.Generic.Queue<float> values;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
public void execute()
{
while (Execute)
{
System.Threading.Thread.Sleep(500);
values.Enqueue(player.x);
UnityEngine.Debug.Log("value");
}
System.IO.StreamWriter write = new System.IO.StreamWriter("values.txt"); // writes to file every 5 seconds
while (values.Count > 0)
{
WriteTime = write.WriteLine(values.Dequeue().ToString());
}
write.Close();
}
public void Lock() // applied Lock threading
{
while(true)
{
lock (this)
{
// dont have anything here yet. Trying to figure out locks
}
}
}
Thank you.
Related
I have an EventSystem for managing my turn-based game in Unity.
public class EventSystem : MonoBehaviour
{
private static List<Action> _commandsQueue = new List<Action>();
private bool _canExecuteCommand = true;
public void AddToQueue(Action command)
{
_commandsQueue.Add(command);
}
private void StartCommandExecution()
{
_commandsQueue[0]();
_canExecuteCommand = false;
}
public void CommandExecutionComplete()
{
_canExecuteCommand = true;
}
public void PlayFirstCommandFromQueue()
{
if (_commandsQueue.Any() && _canExecuteCommand)
{
StartCommandExecution();
}
else
{
Debug.LogError("No Command In Queue");
}
}
}
How do I put a method in Update() until _canExecuteCommand is true again but only for some methods?
It is quite broad what you are trying to do but in general you would use an endless loop within a Coroutine.
You can create a generic routine which invokes any Action you pass in as parameter once a frame like e.g.
private IEnumerator InvokeEveryFrame(Action action)
{
// This looks strange but is okey in a Coroutine as long as you yield somewhere within
while(true)
{
action?.Invoke();
// This tells Unity to "pause" this routine here
// render the current frame and continue from here in the next frame
yield return null;
}
}
So all that's left is starting the routine using MonoBehaviour.StartCoroutine like e.g.
Coroutine routine = StartCoroutine(SomeParameterlessMethod);
or if you need parameters
Coroutine routine = StartCoroutine(() => SomeMethod(x, y, z));
and then at some point later stop it using MonoBehaviour.StopCoroutine and the stored Coroutine reference like e.g.
StopCoroutine(routine);
how exactly you store that reference is up to you of course up to you.
After recovering my data with Firebase using a callback in GetValueAsync().ContinueWith(task..) , I would like to instantiate my prefab in order to see the list of scores for my leaderboard. But, it does nothing and I have no errors. The code simply stops in the callback UseSores as soon as it come across on a 'this' or a 'instantiate'.
public class Leaderboardmanager : MonoBehaviour
{
public GameObject rowLeardBoard;
FirebaseDB_Read read;
float positionX;
int nbRows = 10;
void Start()
{
read = (gameObject.AddComponent<FirebaseDB_Read>());
GetScorePlayer();
}
void GetScorePlayer()
{
read.GetScores(UseScores, "entries/LeaderBoard/", nbRows);
}
void UseScores(IList<FirebaseDB_Read.Score> scores)
{
Debug.Log("arrive here");
positionX = this.transform.position.y;
Debug.Log("does not arrive here");
}
}
Here is to get my data :
public class FirebaseDB_Read : MonoBehaviour
{
public class Score
{
public string UID;
public string score;
public int rank;
}
public void GetScores(Action<IList<Score>> callback, string URL_TO_SCORES, int limit)
{
DatabaseReference scoresRef = FirebaseDatabase.DefaultInstance.GetReference(URL_TO_SCORES);
scoresRef.OrderByChild("score").LimitToLast(limit).GetValueAsync().ContinueWith(task =>
{
DataSnapshot snapshot = task.Result;
IList<Score> objectsList = new List<Score> { };
int i = 1;
foreach (var childSnapshot in snapshot.Children)
{
Score score = new Score();
score.rank = i;
score.UID = childSnapshot.Child("UID").GetValue(true).ToString();
score.score = childSnapshot.Child("score").GetValue(true).ToString();
objectsList.Add(score);
i++;
}
callback(objectsList);
});
}
}
This is an often asked problem in Unity: Because you ContinueWith on a background thread!
Unity isn't thread-safe, meaning that most of the Unity API can only be used within the Unity main thread.
Firebase offers an extension specifically for Unity: ContinueWithOnMainThread which assures that the result is handled in the Unity main thread where accessing the API is valid.
scoresRef.OrderByChild("score").LimitToLast(limit).GetValueAsync().ContinueWithOnMainThread(task =>
{
...
});
As alternative you can use kind of a so called "main thread dispatcher" pattern and make sure that the callback is executed in the main thread on the receiver side. The advantage of this would be that the still expensive operations on your list are all executed on a background thread, not affecting the UI performance
scoresRef.OrderByChild("score").LimitToLast(limit).GetValueAsync().ContinueWith(task =>
{
...
});
but then on receiver side in FirebaseDB_Read
private readonly ConcurrentQueue<Action> _mainThreadActions = new ConcurrentQueue<Action>();
private void Update()
{
if(_mainThreadAction.Count > 0)
{
while(_mainThreadActions.TryDequeue(out var action))
{
action?.Invoke();
}
}
}
void GetScorePlayer()
{
read.GetScores(UseScores, "entries/LeaderBoard/", nbRows);
}
void UseScores(IList<FirebaseDB_Read.Score> scores)
{
// handle this in the next main thread update
_mainThreadActions.Enqueue(() =>
{
Debug.Log("arrive here");
positionX = this.transform.position.y;
Debug.Log("does not arrive here");
}
}
which on the offside of course introduces a little overhead for checking for any new actions in Update of course. So if you plan do use multiple of such background actions make sure to implement them in one central place in order to keep the overhead limited ;)
I have no clue if the thing I want to do has a name or not.
The "Master/Slave locking system" is sadly the best wording I could come up with.
Now to the problem I have...
Imagine you have the following class:
public class Foo
{
public void Master()
{
}
public void Slave1()
{
}
public void Slave2()
{
}
}
What I desire is that the slaves methods (Slave1, Slave2) can run parallel in a multi-threading scenario, but when the master (Master) method is called the slaves method shall be blocked from executing while it is executing, additional all currently running slave methods shall run to completion upon entering the master method.
Something like this (with comments):
public class Foo
{
public void Master()
{
//block slaves from executing
//wait for slaves to finish
//do code...
//unblock slaves
}
public void Slave1()
{
//if blocked by master wait, if not execute
//if currently running when entering master method, let it finish
}
public void Slave2()
{
//if blocked by master wait, if not execute
//if currently running when entering master method, let it finish
}
}
I know I could use lock on all 3 methods but than the Slave1 methods will block each other and thats not what I desire.
public class Foo
{
private readonly object _syncLock = new object();
public void Master()
{
lock (_syncLock) //blocks Slave1, Slave2
{
//run code...
}
}
public void Slave1()
{
lock (_syncLock) //blocks Slave2, Master - dont want that
{
//run code...
}
}
public void Slave2()
{
lock (_syncLock) //blocks Slave1, Master - dont want that
{
//run code...
}
}
}
If possible I would like to have the solution inside this class and not some outside "if you call the methods that way it will do it", the mentioned methods can fire at anytime in a non-ordered way and each method can run muliple times.
If I understand you right, you want to put
Exclusive (Write) lock on Master() (no SlaveN can run)
Shared (Read) lock on each Slave (you can run another SlaveN, but not Master)
If it's your case, please, have a look at ReaderWriterLockSlim:
public class Foo {
private readonly ReaderWriterLockSlim _syncLock = new ReaderWriterLockSlim();
public void Master() {
// Exclusive (write) lock: only Master allowed to run
_syncLock.EnterWriteLock();
try {
//run code...
}
finally {
_syncLock.ExitWriteLock();
}
}
public void Slave1() {
// Read lock: you can run Slave2 (with another Read lock), but not Master
_syncLock.EnterReadLock();
try {
//run code...
}
finally {
_syncLock.ExitReadLock();
}
}
public void Slave2() {
// Read lock: you can run Slave1 (with another Read lock), but not Master
_syncLock.EnterReadLock();
try {
//run code...
}
finally {
_syncLock.ExitReadLock();
}
}
}
I have multiple classes that use a countdown timer, but when I use more than one timer, the output returns the same value, not two separate values specific to their own class.
If I use one timer, everything works perfectly with no issues, it is literally just splitting those timers into separate timers.
I'm sure I have missed something simple here, but can't figure out why they are returning the same output.
Edit: clarity - mfCurrentTime and mfTimeTravelling return the same value, and they should return different values from each timer, but they are merging together as if there is only one timer.
They aren't acting like two separate timers, they are acting as if it is one timer
Edit 2: When used individually, both timers return different values, the correct values that they should be returning. It's only when both timers are running at the same time that the issue occurs.
for example:
mfCurrentTime will always return the current time elapsed as it is continually calling Countdown Update
mfTimeTravelling returns the time elapsed when the bool _mbIsTravelling is true.
When both classes are active, mfCurrentTime is correct, and when the bool is true for mbIsTravelling in the other class, it takes the time of mfCurrentTime. The issue is that they should be two completely separate timers, not one timer.
Edit 3: #Abion47's help lead to the discovery that everything is working as it should, I had just not included a flag for the update in the Update method. I was so fixed on the way I was calling Countdown being the issue, when the real error was a massive oversight on my behalf. I added a condition to the update, and everything is fine.
if(_mbIsTravelling)
{
mIsTravellinTimer.Update();
}
-
This class is using a Countdown timer.
public class Level_TimeTaken : MonoBehaviour
{
public EndOfLevelElement UIElement;
[HideInInspector]
public float mfCurrentTime;
[HideInInspector]
public string msTimeTaken;
private bool _mbLevelIsActive;
private Countdown mLevelTime = new Countdown(9999.0f);
void Start()
{
mLevelTime.Reset();
_mbLevelIsActive = true;
}
void Update()
{
mLevelTime.Update();
TimerRunning();
UIElement.GetTimeTaken(msTimeTaken);
}
private void TimerRunning()
{
if (_mbLevelIsActive)
{
mfCurrentTime = mLevelTime.GetTimeElapsed();
msTimeTaken = mfCurrentTime.ToString("#.00");
}
}
}
This class is also using a Countdown timer.
public class Level_DistanceTravelled : MonoBehaviour
{
public EndOfLevelElement UIElement;
[HideInInspector]
public float mfTimeTravelling;
[HideInInspector]
public string msDistanceTravelled;
private bool _mbIsTravelling;
private Countdown mIsTravellinTimer = new Countdown(6000.0f);
void Start()
{
mIsTravellinTimer.Reset();
}
void Update()
{
mIsTravellinTimer.Update();
DistanceTravelling();
UIElement.GetDistanceTravelled(msDistanceTravelled);
}
private void DistanceTravelling()
{
if (GMM.Instance.Input.ShouldLHorizontalKeyLeft() || GMM.Instance.Input.ShouldLHorizontalKeyRight() || GMM.Instance.Input.ShouldLHorizontalAxis() != 0.0f)
{
_mbIsTravelling = true;
}
else
{
_mbIsTravelling = false;
}
if (_mbIsTravelling)
{
// add math for working out distance so the string displays meters spooled
mfTimeTravelling = mIsTravellinTimer.GetTimeElapsed();
msDistanceTravelled = mfTimeTravelling.ToString("#.00");
}
}
}
and Countdown class, (a generic class for handling timers etc) is here
public class Countdown
{
private float _mfCountdownTime;
private float _mfCurrentTime;
public Countdown(float lfCountdownTime)
{
_mfCountdownTime = lfCountdownTime;
_mfCurrentTime = 0f;
}
public void Update()
{
Update(Time.deltaTime);
}
public void Update(float lfTimeStep)
{
_mfCurrentTime += lfTimeStep;
if (_mfCurrentTime > _mfCountdownTime)
{
_mfCurrentTime = _mfCountdownTime;
}
}
public bool IsComplete()
{
return _mfCurrentTime >= _mfCountdownTime;
}
public void SetComplete()
{
_mfCurrentTime = _mfCountdownTime;
}
public void Reset()
{
_mfCurrentTime = 0f;
}
public float GetTimeElapsed()
{
return _mfCurrentTime;
}
public float GetTimeRemaining()
{
return _mfCountdownTime - _mfCurrentTime;
}
public float GetProgress()
{
return Mathf.Clamp01(_mfCurrentTime / _mfCountdownTime);
}
}
Thanks
In both of your scripts, you are getting the value from GetTimeElapsed. This value is the amount of time that has passed since the Countdown had started, which if both Countdowns were started at the same time would give you the same number.
Perhaps you meant to call GetTimeRemaining, which returns a value that takes the total time given into account? Or maybe GetProgress?
I would like to run code alternatively, so I could stop execution at any moment. Is this code safe?
static class Program
{
static void Main()
{
var foo = new Foo();
//wait for interaction (this will be GUI app, so eg. btnNext_click)
foo.Continue();
//wait again etc.
foo.Continue();
foo.Continue();
foo.Continue();
foo.Continue();
foo.Continue();
}
}
class Foo
{
public Foo()
{
new Thread(Run).Start();
}
private void Run()
{
Break();
OnRun();
}
protected virtual void OnRun()
{
for (var i = 0; i < 5; i++)
{
Console.WriteLine(i);
Break();
}
//do something else and break;
}
private void Break()
{
lock (this)
{
Monitor.Pulse(this);
Monitor.Wait(this);
}
}
public void Continue()
{
lock (this)
{
Monitor.Pulse(this);
Monitor.Wait(this);
}
}
}
Of course I know, that now the application will never ends, but that's not the point.
I need this, because I would like to present steps in some kind of an algorithm and describe what is going on in particular moment, and making everything in one thread would lead to many complications even when using small amount of loops in the code. For example those lines:
for (var i = 0; i < 5; i++)
{
Console.WriteLine(i);
Break();
}
should be then replaced with:
if (this.i < 5)
{
Console.WriteLine(i++);
}
And that is just a small example of what I want to present. The code will be more complicated than a dummy for loop.
I recommend you check out this blog post about implementing fibers.
Code (In case the site goes down.)
public class Fiber
{
private readonly Stack<IEnumerator> stackFrame = new Stack<IEnumerator>();
private IEnumerator currentRoutine;
public Fiber(IEnumerator entryPoint)
{
this.currentRoutine = entryPoint;
}
public bool Step()
{
if (currentRoutine.MoveNext())
{
var subRoutine = currentRoutine.Current
as IEnumerator;
if (subRoutine != null)
{
stackFrame.Push(currentRoutine);
currentRoutine = subRoutine;
}
}
else if (stackFrame.Count > 0)
{
currentRoutine = stackFrame.Pop();
}
else
{
OnFiberTerminated(
new FiberTerminatedEventArgs(
currentRoutine.Current
)
);
return false;
}
return true;
}
public event EventHandler<FiberTerminatedEventArgs> FiberTerminated;
private void OnFiberTerminated(FiberTerminatedEventArgs e)
{
var handler = FiberTerminated;
if (handler != null)
{
handler(this, e);
}
}
}
public class FiberTerminatedEventArgs : EventArgs
{
private readonly object result;
public FiberTerminatedEventArgs(object result)
{
this.result = result;
}
public object Result
{
get { return this.result; }
}
}
class FiberTest
{
private static IEnumerator Recurse(int n)
{
Console.WriteLine(n);
yield return n;
if (n > 0)
{
yield return Recurse(n - 1);
}
}
static void Main(string[] args)
{
var fiber = new Fiber(Recurse(5));
while (fiber.Step()) ;
}
}
"...this will be GUI app..."
Then you probably do not want and will not have sequential code like above in Main().
I.e. the main GUI thread will not execute a serial code like above, but generally be idle, repainting, etc. or handling the Continue button click.
In that event handler you may better use an Auto|ManualResetEvent to signal the worker to proceed.
In the worker, just wait for the event.
I would suggest that any time one considers using Monitor.Wait(), one should write code so that it would work correctly if the Wait sometimes spontaneously acted as though it received a pulse. Typically, this means one should use the pattern:
lock(monitorObj)
{
while(notYetReady)
Monitor.Wait(monitorObj);
}
For your scenario, I'd suggest doing something like:
lock(monitorObj)
{
turn = [[identifier for this "thread"]];
Monitor.PulseAll(monitorObj);
while(turn != [[identifier for this "thread"]])
Monitor.Wait(monitorObj);
}
It is not possible for turn to change between its being checked whether it's the current thread's turn to proceed and the Monitor.Wait. Thus, if the Wait isn't skipped, the PulseAll is guaranteed to awaken it. Note that the code would work just fine if Wait spontaneously acted as though it received a pulse--it would simply spin around, observe turn wasn't set for the current thread, and go back to waiting.