Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by zarch · Sep 01, 2015 at 04:03 PM · networkingapithreading

Multi-threading safely

So im currently working with making a networking solution for unity using .net sockets and so far its not to hard and ive gotten most of the basic jazz done and I do use threading currently but to use the Unity API in the main thread I had to make a task manager but its not threading so each task is one after another as you would think. So I wondered is there a way to make it thread in some way? I thought of making it so the task manager used coroutines but im not sure how to go about it for some reason and i might have low understanding of how they work.

here are some of my scripts:

Here is the container for the Task Manager that is needed and that makes the task that then goes into the queue of tasks

 public class TaskContainer {
 
     static TaskContainer container = null;
     public Queue<Task> TaskQueue = new Queue<Task>();
     public object _queueLock = new object();
 
     public TaskContainer(){
         TaskQueue = new Queue<Task> ();
         _queueLock = new object ();
     }
 
     public void ScheduleTask(Task newTask){
         try{
             lock (_queueLock) {
                 if(TaskQueue.Count < 1000)
                 {
                     Debug.Log(TaskQueue.Count);
                     TaskQueue.Enqueue(newTask);
                 }
             }
         }catch(ThreadInterruptedException e){
             Debug.Log(e);
         }
     } 
 
     public static TaskContainer GetInstance(){
 
         if (container == null) {
             container = new TaskContainer();
         }
 
         return container;
     }
 }

This is the actual tasker that does it

 public delegate void Task();
 
 public class TaskManager : MonoBehaviour {
 
     TaskContainer container = null;
 
     void Start()
     {
         container = TaskContainer.GetInstance ();
     }
 
     // Update is called once per frame
     void Update () {
         if (container != null) {
             lock (container._queueLock) {
                 if (container.TaskQueue.Count > 0) {
                     container.TaskQueue.Dequeue () ();
                 }
             }
         }
     }
 }


and here is an example of one of the functions that calls those and is needed to be done thread like

 TaskContainer container = TaskContainer.GetInstance ();
 
     public void serversinstantiate(string prefabName, string x, string y, string z, string actorId, string clientId)
     {
         float px = float.Parse (x, CultureInfo.InvariantCulture.NumberFormat);
         float py = float.Parse (y, CultureInfo.InvariantCulture.NumberFormat);
         float pz = float.Parse (z, CultureInfo.InvariantCulture.NumberFormat);
         int id = System.Convert.ToInt32 (actorId);
         int cliId = System.Convert.ToInt32 (clientId);
 
         Debug.Log ("Intantiate this: " + prefabName + " at this place: " + px + " " + py + " " + pz); 
 
         if (container != null) {
             Debug.Log("in if");
             container.ScheduleTask (new Task (delegate {
                 Debug.Log ("in task " + prefabName);
                 GameObject newObject = (GameObject)GameObject.Instantiate (Resources.Load (prefabName), new Vector3 (px, py, pz), Quaternion.identity);
                 newObject.GetComponent<AltimitView>().actorId = id;
                 if(AltimitNetowrk.ClientId == cliId){
                     newObject.GetComponent<AltimitView>().isMine = true;
                 }
                 GetComponent<NetworkManager>().NetowrkObjects.Add(newObject);
             }));
         }
     }
Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Scribe · Sep 01, 2015 at 04:05 PM 0
Share

Unity API is not thread safe, so you can not thread anything using it.

Coroutines are not threads, but let you balance out performance by perfor$$anonymous$$g calculations over several frames.

avatar image zarch · Sep 01, 2015 at 04:53 PM 0
Share

I understand that but that might be how i have to do it unless there is another way to update multiple transforms positions potentially at the same time or i do magic and just do some animation as if its always updating over time.

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Bunny83 · Sep 01, 2015 at 05:56 PM

Your example "task" doesn't seem to contain anything that would be close to be worth of "threading".

I guess your problem is mainly the way your "task scheduler" is implemented. It always processes only one task per frame. So if you generate 1000 tasks and your game runs at 60 fps it takes about 17 seconds to process the whole list. That's actually a bad implementation ^^. Usually you can execute far more tasks per frame. The usual implementation simply processes all pending tasks at once. However if the tasks are quite demanding you might want to implement a watchdog.

But first of all the way you pop a task is horrible inefficient ^^. You lock your queue and keep it locked until your task is actually finished. You only have to lock it for the actual dequeuing.

It should look something like that:

 Task DequeueTask()
 {
     if (container == null) 
         return null;
     Task task = null;
     lock (container._queueLock) 
     {
         if (container.TaskQueue.Count > 0) {
             task = container.TaskQueue.Dequeue ();
         }
     }
     return task;
 }
 
 void Update () 
 {
     Task current = DequeueTask();
     float timeout = Time.realtimeSinceStartup + 0.04f;
     while(current != null)
     {
         current();
         if (Time.realtimeSinceStartup > timeout)
             break;
         current = DequeueTask();
     }
 }

The 0.04s equals about 25 fps. however this only takes the time into account that the tasks need to process and not the rest of your game. This scheduler will schedule at least one task per frame even when the frame rate has already dropped below 25fps. Furthermore it will schedule as many task as possible within one frame before hitting the time cap.

Time.realtimeSinceStartup is a quite unprecise time, but it should be enough for this case. You can instead use a Stopwatch or High performance timer. Just in case: You can't use Time.time since that will not advance during a frame. So if you have an never ending amount of tasks it will never terminate since Time.time is also stuck. Though that case should never happen as that means your task queue is filling faster than you can process it ^^.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

Threading with UDPClient - Editor Freezing 2 Answers

UnityWebRequest ContentType not Overriding 4 Answers

Can I connect to a server using the IP adress and the port with the new Unity 5 Networking API?? 0 Answers

NetworkMatch Request Error Out of memory 1 Answer

threading if() problem 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges