Threading in unity with C# for optimisation - c#

So here is my code: the idea is that in the input system class we find some data from the user, then listen to this data from the threading class and process it in a new thread, then we return the processed data to the main thread.
It works, but it is slow ... why is this?
I'm new to coding, so hopefully that explains the errors ...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Threading;
public class InputSystem : MonoBehaviour
{
public EventHandler<dataStore> onRequest;
public class dataStore : EventArgs
{
public int[] dataPass;
}
public int[] newData;
void Start()
{
int[] test = new int[] { 6, 6, 6 };
newData = test;
}
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
onRequest?.Invoke(this, new dataStore { dataPass = newData });
}
}
}
public class StartThread : MonoBehaviour
{
void Start()
{
InputSystem input = GetComponent<InputSystem >();
input.onRequest += findPath;
}
requestData pData;
returnData rData;
public void findPath(object sender, InputSystem.dataStore data)
{
pData = data.dataToPass;
RequestPath(method);
}
public static void RequestPath(Action doThing)
{
ThreadStart thread = delegate
{
doThing();
};
thread.Invoke();
}
public Queue<Action> toRun = new Queue<Action>();
public void method()
{
PathAlg test = new PathAlg();
Action toQueue = () =>
{
requestData data = pData;
rData.data = test.method(data);
};
lock (toRun)
{
toRun.Enqueue(toQueue);
}
}
void Update()
{
while (toRun.Count > 0)
{
lock (toRun)
{
Action runThis = toRun.Dequeue();
runThis();
foreach(int n in rData)
{
print(n);
}
}
}
}
}
public struct requestData
{
public int[] data;
}
public struct returnData
{
public int[] data;
}
public class pathAlg
{
public int[] method(requestData data)
{
int[] example = new int[data.Length];
for(int i = 0; i< example.Length; i++)
{
example[i] = i+1;
}
return example;
}
}

Solved this problem by using coroutines rather than threads.

Related

Required solution for Thread Constructor and solution to start thread for my code

I am trying to assign value to my variable in default constructor and Thread Construction. However, I am unable to identify how to solve this issue.
I have created a for loop through which I am assigning my value as well as to Start the Thread.
How can I solve ThreadStart(InitializeServer(I))?
-> Error: Method name expected
What is the other way around for this. ServerInitialization.Start();
-> If I use workerThread.Start() will all individual thread would start? Example Such as Server 1, Server 2?
ServerInitialization.cs
using System;
using System.Threading;
namespace MyApplication
{
public class ServerInitialization
{
public int serverID;
static private int ServersInStore = MainApplication.numofServers;
public ServerInitialization(int serverNum)
{
this.serverID = serverNum;
}
public static void InitializeServer(int sId)
{
ServerInitialization _id = new ServerInitialization(sId);
_id.serverID = sId;
}
public static void AssignServer(int totalServers)
{
for (int i = 0; i<totalServers; ++i)
{
Thread workerThread = new Thread(new ThreadStart(InitializeServer(i)));
ServerInitialization.Start();
}
}
}
MainApplication.cs
using System;
using System.Threading;
namespace MyApplication
{
public class MainApplication
{
public static int numofServers = 0;
static void Main(string[] args)
{
Console.WriteLine("How servers required?");
numofServers = int.Parse(Console.ReadLine());
ServerInitialization.AssignServer(numofServers);
}
}
}
Recreating my C# issue in Java project.
GenerateServer.java
import java.util.Scanner;
public class GenerateServer {
protected static int NumOfServers=4;
public static void main(String[] args) {
// TODO Auto-generated method stub
Server.InitializeServer();
}
}
Server.java
public class Server implements Runnable{
private int serverID;
//private Customer atCounter;
static private int ServersInStor=GenerateServer.NumOfServers;
public Server(int serverID)
{
this.serverID=serverID;
}
public static void InitializeServer()
{
for (int i=0; i<GenerateServer.NumOfServers; ++i)
{
Thread Server = new Thread(new Server(i));
Server.start();
}
}
#Override
public void run() {
// TODO Auto-generated method stub
}
}
Looks like you can just use an anonymous lambda function
Thread workerThread = new Thread(new ThreadStart(() => InitializeServer(i)));
Or in short:
Thread workerThread = new Thread(() => InitializeServer(i));

How to pass a List<Interface> and an implemented method from another class

I have a Game Manager, which is used to manage the execution order of specific Unity callbacks (FixedUpdate, Update and LateUpdate) in all the other scripts.
Specifically, I wrote these 3 interfaces:
public interface IFixedAt {
bool IsActive { get; }
void FixedAt();
}
public interface IUpdateAt {
bool IsActive { get; }
void UpdateAt();
}
public interface ILateUpdateAt {
bool IsActive { get; }
void LateUpdateAt();
}
These interfaces are implemented in game objects' scripts, where needed, like this for example:
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour, IUpdateAt, ILateUpdateAt {
[SerializeField]
bool isActive = true;
public bool IsActive {
get {
return (isActive && gameObject.activeInHierarchy);
}
}
public void UpdateAt() {
// Do stuff in Update
}
public void LateUpdateAt() {
// Do stuff in Late Update
}
}
The Game Manager script gets at Awake the reference to all scripts which implement the interfaces, creating a List<Interface> and then uses the list at runtime to execute the callbacks only where needed:
using UnityEngine;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
public List<GameObject> GameObjectsWithScripts;
List<IFixedAt> fixedAtList { get; set; }
List<IUpdateAt> updateAtList { get; set; }
List<ILateUpdateAt> lateUpdateAtList { get; set; }
private void Awake() {
PopulateAllLists();
}
private void FixedUpdate() {
if (fixedAtList != null) {
for (int i = 0; i < fixedAtList.Count; i++) {
if (fixedAtList[i].IsActive)
fixedAtList[i].FixedAt();
}
}
}
private void Update() {
if (updateAtList != null) {
for (int i = 0; i < updateAtList.Count; i++) {
if (updateAtList[i].IsActive)
updateAtList[i].UpdateAt();
}
}
}
private void LateUpdate() {
if (lateUpdateAtList != null) {
for (int i = 0; i < lateUpdateAtList.Count; i++) {
if (lateUpdateAtList[i].IsActive)
lateUpdateAtList[i].LateUpdateAt();
}
}
}
void PopulateAllLists() {
fixedAtList = PopulateList<IFixedAt>(GameObjectsWithScripts);
updateAtList = PopulateList<IUpdateAt>(GameObjectsWithScripts);
lateUpdateAtList = PopulateList<ILateUpdateAt>(GameObjectsWithScripts);
}
List<T> PopulateList<T> (List<GameObject> goScripts) {
//Scans the GOs list and adds existent interface elements to the list
var list = new List<T>();
for (int i = 0; i < goScripts.Count; i++) {
if (goScripts[i].GetComponent<T>() != null) {
list.Add(goScripts[i].GetComponent<T>());
}
}
//Returns list (null if list is empty)
if (list.Count > 0) {
return list;
}
else {
return null;
}
}
}
Now, the question for which I'm having trouble in understanding if it's possible to do, and if yes, how.
As you can see, the code inside FixedUpdate, Update and LateUpdate is basically the same: it iterates on the specific List, checks if the current element is active, and if true it executes the proprietary callback.
What I want to know is if it's possible to create a generic method that can be called from inside the three callbacks, and passing to it the List to iterate on and the specific method to call for that List, something like this in pseudo-code:
private void FixedUpdate() {
Method (fixedAtList, FixedAt() );
}
private void Update() {
Method (updateAtList, UpdateAt() );
}
private void LateUpdate() {
Method (lateUpdateAtList, LateUpdateAt() );
}
private void Method<T> (List<T> list, Action method) {
if (list != null) {
for (int i = 0; i < list.Count; i++) {
if (list[i].IsActive)
list[i].method();
}
}
}
I've tried different things, to no success, and atm I'm clueless about how to do that. Any help will be very appreciated.
First you need an interface that covers the IsActive method.
public interface IActive {
bool IsActive { get; }
}
public interface IFixedAt : IActive {
void FixedAt();
}
public interface IUpdateAt : IActive {
void UpdateAt();
}
public interface ILateUpdateAt : IActive {
void LateUpdateAt();
}
Then you need to use the generic Action<T> and then you can pass in lambdas
private void FixedUpdate() {
Method (fixedAtList, f => f.FixedAt() );
}
private void Update() {
Method (updateAtList, u => u.UpdateAt() );
}
private void LateUpdate() {
Method (lateUpdateAtList, l => l.LateUpdateAt() );
}
private void Method<T> (List<T> list, Action<T> method) where T : IActive {
if (list != null) {
for (int i = 0; i < list.Count; i++) {
if (list[i].IsActive)
method(list[i]);
}
}
}

How do i pass variables from class to a new class?

I have this class wich I will make an instance for it in Form1 later that pass variables from Form1 to the class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GatherLinks
{
class WebcrawlerConfiguration
{
public string url;
public int levels;
public string mainurl;
public Dictionary<string,List<string>> localy;
public bool removeext;
public bool downloadcontent;
public int failedUrls;
public bool toCancel;
public System.Threading.ManualResetEvent busy;
public WebcrawlerConfiguration()
{
}
}
}
How do I make that this class will get the variables from Form1 ?
Each variable in the class should get the variable in Form1 when I will make an instance for the class.
Then I have this class:
class BackgroundWebCrawling
{
int counter = 0;
List<string> WebSitesToCrawl;
BackgroundWorker mainBackGroundWorker;
BackgroundWorker secondryBackGroundWorker;
WebCrawler webcrawler1;
WebcrawlerConfiguration webcrawlerCFG;
public BackgroundWebCrawling()
{
mainBackGroundWorker = new BackgroundWorker();
mainBackGroundWorker.DoWork += mainBackGroundWorker_DoWork;
}
private void mainBackGroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < WebSitesToCrawl.Count; i++)
{
if (counter >= 3)
{
Thread.Sleep(10);
}
else
{
webcrawler1 = new WebCrawler(webcrawlerCFG);
counter++;
secondryBackGroundWorker = new BackgroundWorker();
secondryBackGroundWorker.DoWork += secondryBackGroundWorker_DoWork;
}
}
}
private void secondryBackGroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (offlineOnline == true)
{
offlinecrawling(f, levelsToCrawl, e);
}
else
{
webcrawler1.webCrawler(
}
counter--;
}
In the bottom here im doing: webcrawler1.webCrawler(
The function webCralwer should get all the variables from the first class WebcrawlerConfiguration.
This is how the WebCrawler function looks like:
public List<string> offlinecrawling(string url, int levels, string mainurl, Dictionary<string, List<string>> localy, bool removeext, bool downloadcontent, int failedUrls, bool toCancel, System.Threading.ManualResetEvent busy)
So now when im doing webcrawler1.webCrawler(
It's asking for all the variables...But I want to pass them somehow from the WebcrawlerConfiguration.
How can I do it ?

How can i transmit the sender as an eventarg

Instance X of a class register to the change event of instances Y of the same class.
I want to update X if Y is changed, but i dont want to use the static keyword all over the class. Is there a way to transmit the recipient of the event in the eventargs?
Here is some example code with an NUnit tests to illustrate where my problem lies exactly. I compiled and ran it. Two tests just verify the programming. The failing test illustrates my problem.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace Eventtest
{
public class DependencyChain
{
public static int demonstrationcount = 0;
private String hiddenstring = "";
public String visiblestring
{
get { return hiddenstring; }
set
{
hiddenstring = value;
NotifyOnStringChanged();
}
}
private void NotifyOnStringChanged()
{
if (changed != null)
{
changed(this, EventArgs.Empty);
}
}
public EventHandler changed;
private EventHandler Observer = new EventHandler((o, e) => {
DependencyChain sender = (o as DependencyChain);
demonstrationcount++;
//THE FOLLOWING DOES NOT WORK SINCE "this" IS NOT STATIC
//DependencyChain recipient = this;
//recipient.visiblestring = sender.visiblestring;
});
public DependencyChain(string initialstring)
{
this.visiblestring = initialstring;
}
public DependencyChain(DependencyChain other)
{
this.visiblestring = other.visiblestring;
other.changed += Observer;
}
public override string ToString()
{
return visiblestring;
}
}
[TestFixture]
class Eventtest
{
[SetUp]
public void ResetStaticCounter()
{
DependencyChain.demonstrationcount = 0;
}
[Test]//PASS
public void ShouldInitialiseAndCopyValues()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Assert.AreEqual(X.ToString(), Y.ToString());
}
[Test]//PASS
public void ShouldCallObserverOnChange()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Assert.AreEqual(0, DependencyChain.demonstrationcount);
Y.visiblestring = "changed";
Assert.AreEqual(1, DependencyChain.demonstrationcount);
}
[Test]//FAIL
public void ShouldChangeStringOnChange()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Y.visiblestring = "changed";
Assert.AreEqual(X.ToString(), Y.ToString());
}
}
}
I think you only have to move the initialization of Observer to a constructor of DependencyChain, so you can capture this.

BindingList not updating bound ListBox

I have a ListBox that is bound to a BindingList. The BindingList is built up when a third party application raises an event. I can see the BindingList being bound correctly... but nothing enters the ListBox. I have used the exact same logic with some of my own custom types and it usually works very well.
Form class
private Facade.ControlFacade _controlFacade;
public UavControlForm()
{
InitializeComponent();
_controlFacade = new UavController.Facade.ControlFacade();
UpdateEntityListBox();
}
private void UpdateEntityListBox()
{
lsbEntities.DataSource = _controlFacade.GetEntityTally();
lsbEntities.DisplayMember = "InstanceName";
}
Facade class
private Scenario _scenario;
public ControlFacade()
{
_scenario = new Scenario();
}
public BindingList<AgStkObject> GetEntityTally()
{
BindingList<AgStkObject> entityTally = _scenario.EntityTally;
return entityTally;
}
Scenario class
private static BindingList<IAgStkObject> _entityTally = new BindingList<AgStkObject>();
public Scenario()
{
if (UtilStk.CheckThatStkIsAvailable())
{
UtilStk.StkRoot.OnStkObjectAdded += new IAgStkObjectRootEvents_OnStkObjectAddedEventHandler(TallyScenarioObjects);
UtilStk.StkRoot.OnStkObjectDeleted += new IAgStkObjectRootEvents_OnStkObjectDeletedEventHandler(TallyScenarioObjects);
}
}
private void TallyScenarioObjects(object sender)
{
List<AgStkObject> tallyOfStkObjects = UtilStk.GetRunningTallyOfAllStkObjects();
List<string> stkObjectNames = UtilStk.GetInstanceNamesOfStkObjects(tallyOfStkObjects);
foreach (string stkObjectName in stkObjectNames)
{
if (!SearchFlightUavTallyByName(stkObjectName))
{
if (!SearchLoiterUavTallyByName(stkObjectName))
{
if (!SearchEntityTallyByName(stkObjectName))
{
int i = stkObjectNames.IndexOf(stkObjectName);
_entityTally.Add(tallyOfStkObjects[i]);
}
}
}
}
}
I can see the event fire from the third-party application - this adds an entity to _entityList as desired, but noothing is added to lsbEntities - why?
(jump right to the last example if you want to see it fixed etc)
Threads and "observer" patterns (such as the data-binding on winforms) are rarely good friends. You could try replacing your BindingList<T> usage with the ThreadedBindingList<T> code I used on a previous answer - but this combination of threads and UI is not an intentional use-case of winforms data-binding.
The listbox itself should support binding via list notification events (IBindingList / IBindingListView), as long as they arrive form the right thread. ThreadedBindingList<T> attempts to fix this by thread-switching on your behalf. Note that for this to work you must create the ThreadedBindingList<T> from the UI thread, after it has a sync-context, i.e. after it has started displaying forms.
To illustrate the point that listbox does respect list-change notifications (when dealing with a single thread):
using System;
using System.ComponentModel;
using System.Windows.Forms;
class Foo
{
public int Value { get; set; }
public Foo(int value) { Value = value; }
public override string ToString() { return Value.ToString(); }
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
using(var form = new Form())
using (var lst = new ListBox())
using (var timer = new Timer())
{
var data = new BindingList<Foo>();
form.Controls.Add(lst);
lst.DataSource = data;
timer.Interval = 1000;
int i = 0;
timer.Tick += delegate
{
data.Add(new Foo(i++));
};
lst.Dock = DockStyle.Fill;
form.Shown += delegate
{
timer.Start();
};
Application.Run(form);
}
}
}
and now with added threading / ThreadedBindingList<T> (it doesn't work with the regular BindingList<T>):
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
class Foo
{
public int Value { get; set; }
public Foo(int value) { Value = value; }
public override string ToString() { return Value.ToString(); }
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
using(var form = new Form())
using (var lst = new ListBox())
{
form.Controls.Add(lst);
lst.Dock = DockStyle.Fill;
form.Shown += delegate
{
BindingList<Foo> data = new ThreadedBindingList<Foo>();
lst.DataSource = data;
ThreadPool.QueueUserWorkItem(delegate
{
int i = 0;
while (true)
{
data.Add(new Foo(i++));
Thread.Sleep(1000);
}
});
};
Application.Run(form);
}
}
}
public class ThreadedBindingList<T> : BindingList<T>
{
private readonly SynchronizationContext ctx;
public ThreadedBindingList()
{
ctx = SynchronizationContext.Current;
}
protected override void OnAddingNew(AddingNewEventArgs e)
{
SynchronizationContext ctx = SynchronizationContext.Current;
if (ctx == null)
{
BaseAddingNew(e);
}
else
{
ctx.Send(delegate
{
BaseAddingNew(e);
}, null);
}
}
void BaseAddingNew(AddingNewEventArgs e)
{
base.OnAddingNew(e);
}
protected override void OnListChanged(ListChangedEventArgs e)
{
if (ctx == null)
{
BaseListChanged(e);
}
else
{
ctx.Send(delegate
{
BaseListChanged(e);
}, null);
}
}
void BaseListChanged(ListChangedEventArgs e)
{
base.OnListChanged(e);
}
}

Categories

Resources