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 Cambesa · Feb 28, 2018 at 03:45 PM · servermultithreadingfilestreamblocking

FileStream on separate Thread seems to block the main thread

When downloading something through my local server in Unity, the editor stops responding until all downloads are complete. How can that happen when it's running on a separate thread?

Here's the code:

 using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Net;
 using System.Threading;
 using UnityEngine;
 
 public class LocalServer
 {
     public bool runListener = true;
     private string prefix;
     private string baseDirectory = "M:/ftp backup/";
     private volatile int chosenPort;
 
     public LocalServer(int port)
     {
         prefix = string.Format("http://+:{0}/", port);
         chosenPort = port;
         Thread listenerThread = new Thread(LocalServerThread);
         listenerThread.Start();
     }
 
     public void LocalServerThread()
     {
         HttpListener listener = new HttpListener();
         listener.Prefixes.Add(prefix);
         listener.Start();
         Debug.Log("<color=green>Started local web server on port: " + chosenPort + "</color>");
         while (runListener)
         {
             IAsyncResult result = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
             result.AsyncWaitHandle.WaitOne();
         }
         listener.Close();
         Debug.Log("<color=green>Stopped local web server</color>");
     }
 public void ListenerCallback(IAsyncResult result)
     {
         HttpListener listener = (HttpListener)result.AsyncState;
         HttpListenerContext context = listener.EndGetContext(result);
         string fileNameComplete = context.Request.Url.AbsolutePath.Substring(1).Replace("%20", " ");
         string pathComplete = baseDirectory + fileNameComplete;
         Debug.Log(pathComplete + " requested to LocalServer");
 
         using (Stream fileStream = new FileStream(pathComplete, FileMode.Open))
         {
             byte[] buffer = new byte[fileStream.Length];
             fileStream.Read(buffer, 0, (int)fileStream.Length);
             context.Response.ContentLength64 = fileStream.Length;
             context.Response.ContentType = SimpleHTTPServer.GetMimeType(fileNameComplete);
             context.Response.StatusCode = (int)HttpStatusCode.OK;
             context.Response.AddHeader("Cache-Control", "no-cache");
             context.Response.OutputStream.Write(buffer, 0, buffer.Length);
             context.Response.Close();
         }
     }
 }

EDIT: When using an external program to download a file from the server running in Unity, Unity does not block. When downloading a file through Unity from an external program that runs the same code, Unity does not block either. So it seems like the combination of uploading and downloading inside Unity actually makes the main Unity thread block. Does someone have an idea why this happens?

EDIT 2: Only DirectShow blocks, MediaFoundation does not, this seems to be a media player related problem, odd that it's specifically happens when DirectShow downloads to the same application as the one uploading it.

Comment
Add comment
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

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by Bunny83 · Feb 28, 2018 at 04:12 PM

Starting threads while testing inside the editor can be dangerous. You have to make sure that you properly terminate all threads. Stopping playmode does not stop other threads. There are some things a bit strange about your "HTTP server". First of all your listener thread always waits for the current request to finish. So it can only process one request at a time. You shouldn't wait for the request to finish in the listener thread as this makes the seperate request threads pointless. edit
Well actually waiting for the async result of "BeginGetContext" is fine and actually required. Since the handling of the request is handled by another seperate thread. When BeginGetContext "finishes" it means it has started another thread which is handling the request and we can wait for the next request. So this part was actually right.


Currently you encapculated the HttpListener completely inside the "LocalServerThread" method. However you don't have a reliable way to stop the listener. Setting "runListener" to false will not terminate the thread until another request arrived. You should call Stop on the listener when you want to stop it. In general the listener object should be a member variable of your "LocalServer" class.

Comment
Add comment · Show 3 · 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
avatar image Cambesa · Mar 01, 2018 at 03:45 PM 0
Share

I replaced WaitOne(); by Thread.Sleep(10); and now the thread is ter$$anonymous$$ated successfully. The runListener boolean is set to false on application quit and stopped local webserver is logged which means it got out of the while loop. Thanks for pointing it out. I specifically chose not to use thread.abort or listener.stop so I would not corrupt an ongoing process.

After you pointed it out I thought Wait.One would actually wait until the complete ListenerCallback would finish so I think using Thread.Sleep helps for parallel downloads. I'm not sure though I would have to test it, but before that I still need to find what's blocking the Unity main thread while the file is being downloaded.

I made the listener a member variable but I'm not actually doing anything with it.

avatar image Bunny83 Cambesa · Mar 02, 2018 at 08:14 PM 1
Share

Ins$$anonymous$$d of a Thread.Sleep you could simple do:

 result.AsyncWaitHandle.WaitOne(100);

WaitOne will return false when the timeout is reached and true when it actually completed the "BeginGetContext" request. This allows it to answer multiple requests in quick succession while it keeps spinning the thread every 100 ms.


The HttpListener has a Stop method you should call when you want to stop listening. This should actually "complete" any pending "BeginGetContext". Calling "Stop" on the listener should not "corrupt" a currently running request as the request is handled on another thread entirely since you use the async variant. I just tested it by manually shutting down the listener while a download is still running. I created an artificial slow down by sending junk data in 100 seperate chunks and do a Debug.Log for each chunk. When calling Stop on the listener the listener thread will ter$$anonymous$$ate while the actual context thread for currently running requests keep running.


However keep in $$anonymous$$d that when you exit playmode the threads will keep running, however when you restart playmode or when Unity recompiles your scripts the managed environment gets reloaded which will ter$$anonymous$$ate all managed threads.


I doubt that your server code is actually responsible for blocking the editor. I've tried downloading from external application (firefox) and i tried downloading using WWW in a coroutine. In any case it did not block the editor. Also even when i stopped the listener thread running downloads will continue to run even when i'm back in edit mode. However the download does stop when i re-enter playmode or if Unity does a recompile / environment reload.


You haven't mentioned where and how you actually download the files. Since you mentioned DirectShow you probably use some native code stuff in your application.

avatar image Cambesa Bunny83 · Mar 05, 2018 at 01:56 PM 0
Share

Thank you for your advice, I improved the server code. DirectShow is the one downloading something from the server in Unity and apparently DirectShow is the one blocking the main thread until everything is downloaded. I replaced the media player/downloader with $$anonymous$$ediaFoundation and the main thread is not blocked anymore.

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

77 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Unity networking tutorial? 6 Answers

Unity based server, running each level in separate engine 0 Answers

Download binary file from my FTP server 0 Answers

smartfoxserver keeps me logged in after exiting game 1 Answer

Unity Master Server - Good to use? 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