The Netduino forums have been replaced by new forums at community.wildernesslabs.co.
This site has been preserved for archival purposes only
and the ability to make new accounts or posts has been turned off.
Just picked up a Netduino Plus last week! Already hooked on it...
Since the .NET Micro Framework only has ThreadStart and not ParameterizedThreadStart, how are you guys passing parameters to your threads? The idea is the Netduino acts as a server, flags a custom EventHandler when a request is received, and passes the request along to be processed on a separate thread.
I'm used to doing something like this:
public static void Main()
{
...
// Watch for requests
server.Request += new RequestEventHandler(server_Request);
...
}
static void server_Request(object sender, RequestEventArgs e)
{
// Process the request on a new thread
ParameterizedThreadStart threadStart = new ParameterizedThreadStart(ProcessRequest);
Thread thread = new Thread(threadStart);
thread.Start(e.Request);
}
static void ProcessRequest(object request)
{
...
}
Here some code you could try, remember to put a lock around any shared resources you are accessing and make sure no thread dies. To do this put a Try catch around anything that may cause an exception in the thread itself.
And debugging is always fun with multiple threads.
using System;
using Microsoft.SPOT;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
namespace NetduinoPlusApplication1
{
public delegate void WorkFinishedHandler(Exception ex, WorkerThread requestWorker);
public class Program
{
public static void Main()
{
// write your code here
Socket socket = null;
WorkerThread workerThread = new WorkerThread(socket, WorkFinishedHandler);
workerThread.Start();
}
private static void WorkFinishedHandler(Exception ex, WorkerThread requestWorker)
{
Debug.Print("All done:");
}
}
public class WorkerThread
{
private Thread currentThread = null;
private WorkFinishedHandler _WorkFinishedHandler = null;
public WorkerThread(Socket nonBlockingSocket, WorkFinishedHandler workFinishedHandler)
{
_WorkFinishedHandler = workFinishedHandler;
}
/// <summary>
/// Start the server thread.
/// </summary>
public void Start()
{
// start thread
this.currentThread = new Thread(ThreadMain);
currentThread.Start();
Debug.Print("Started thread " + currentThread.GetHashCode().ToString());
}
/// <summary>
/// Allows an external process to stop the thread completely.
/// </summary>
public void Stop()
{
Debug.Print("Stopping this thread.");
//bring down the thread.
this.currentThread.Abort();
}
private void ThreadMain()
{
try
{
;//do all the threads work here.
}
catch (Exception ex)
{
Debug.Print("EX ." + ex.Message);
}
_WorkFinishedHandler(null, this);// passes back a reference to itself to help with dequeueing.
}
/// <summary>
/// implement IDisposable
/// </summary>
public void Dispose()
{
Stop();
}
}
}
Not really sure what you suggested, but I don't think it'll work for me. I won't know what function or class to look to until a Request event gets raised.
Anyone else ever run into this? I can't have been the first...
Hi
Here some code you could try, remember to put a lock around any shared resources you are accessing and make sure no thread dies. To do this put a Try catch around anything that may cause an exception in the thread itself.
And debugging is always fun with multiple threads.
using System;
using Microsoft.SPOT;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
namespace NetduinoPlusApplication1
{
public delegate void WorkFinishedHandler(Exception ex, WorkerThread requestWorker);
public class Program
{
public static void Main()
{
// write your code here
Socket socket = null;
WorkerThread workerThread = new WorkerThread(socket, WorkFinishedHandler);
workerThread.Start();
}
private static void WorkFinishedHandler(Exception ex, WorkerThread requestWorker)
{
Debug.Print("All done:");
}
}
public class WorkerThread
{
private Thread currentThread = null;
private WorkFinishedHandler _WorkFinishedHandler = null;
public WorkerThread(Socket nonBlockingSocket, WorkFinishedHandler workFinishedHandler)
{
_WorkFinishedHandler = workFinishedHandler;
}
/// <summary>
/// Start the server thread.
/// </summary>
public void Start()
{
// start thread
this.currentThread = new Thread(ThreadMain);
currentThread.Start();
Debug.Print("Started thread " + currentThread.GetHashCode().ToString());
}
/// <summary>
/// Allows an external process to stop the thread completely.
/// </summary>
public void Stop()
{
Debug.Print("Stopping this thread.");
//bring down the thread.
this.currentThread.Abort();
}
private void ThreadMain()
{
try
{
;//do all the threads work here.
}
catch (Exception ex)
{
Debug.Print("EX ." + ex.Message);
}
_WorkFinishedHandler(null, this);// passes back a reference to itself to help with dequeueing.
}
/// <summary>
/// implement IDisposable
/// </summary>
public void Dispose()
{
Stop();
}
}
}
After Magpie got me thinking in the right direction, I finally figured it out... since you can't pass parameters to a thread, I created a class to hold all my parameters for me and passed a method from that class as the thread delegate:
static void server_Request(object sender, RequestEventArgs e)
{
// Process the request on a new thread
Thread thread = new Thread(e.Request.Process)
{
Priority = ThreadPriority.Highest
};
thread.Start();
}
public class Request
{
public string Details { get; set; }
public Request(string details)
{
this.Details = details;
}
public void Process()
{
// Process request in here
}
}
This may be too late if you like what you have, but I've used lambda expressions to provide this behavior. See below modification in the server_Request method. I wasn't sure what type your "Request" itself is, substitute that as appropriate.
This also allows you to make the parameter to your thread method strongly-typed (instead of object).
public static void Main()
{
...
// Watch for requests
server.Request += new RequestEventHandler(server_Request);
...
}
static void server_Request(object sender, RequestEventArgs e)
{
// Create a local reference of the request to prevent someone possibly changing the value of e.Request before the thread actually begins.
// It's unlikely - but possible.
RequestType request = e.Request;
// Process the request on a new thread
Thread thread = new Thread(() => ProcessRequest(request));
thread.Start(e.Request);
}
static void ProcessRequest(RequestType request)
{
...
}
Hi Cabadam
You need to put a lock on your shared resources, so that the threads are forced to wait if another thread is already using them.
Just show you it is possible.
I have a multithreaded webserver running currently 2-6 threads.
1 thread for the logger
1 thread for the main webserver
and up to 4 threads that can come alive as requests come in.
Be aware the graph takes over a minute to download. so if you click on it please wait. It loads about 6 pages and a lot of javascript, thats why it takes to long.
I have to revise my http caching headers.
Please dont DOS me. It wouldn't take much.
Update: Had first crash in 6 days and 2500 requests, one hour after posting this link. Oh well back to the drawing board.
It is nowhere near finished so I cant post the code,
Yeesssss! That is exactly what I'm looking for! I really wanted the processing to be done in Main and not the class itself, so this is perfect.
Here is my updated code with Cabadam's suggestion:
public static void Main()
{
...
// Watch for requests
server.Request += new RequestEventHandler(server_Request);
...
}
static void server_Request(object sender, RequestEventArgs e)
{
// Process the request on a new thread
Thread thread = new Thread(() => ProcessRequest(e.Request))
{
Priority = ThreadPriority.Highest
};
thread.Start();
}
static void ProcessRequest(Request request)
{
...
}
Thanks!
This may be too late if you like what you have, but I've used lambda expressions to provide this behavior. See below modification in the server_Request method. I wasn't sure what type your "Request" itself is, substitute that as appropriate.
This also allows you to make the parameter to your thread method strongly-typed (instead of object).
Hi Cabadam
You need to put a lock on your shared resources, so that the threads are forced to wait if another thread is already using them.
Just show you it is possible.
I have a multithreaded webserver running currently 2-6 threads.
1 thread for the logger
1 thread for the main webserver
and up to 4 threads that can come alive as requests come in.
Be aware the graph takes over a minute to download. so if you click on it please wait. It loads about 6 pages and a lot of javascript, thats why it takes to long.
I have to revise my http caching headers.
Please dont DOS me. It wouldn't take much.
Update: Had first crash in 6 days and 2500 requests, one hour after posting this link. Oh well back to the drawing board.
It is nowhere near finished so I cant post the code,
I didn't mean to say it was impossible. To me it just sounded like I hit a bug in the framework and/or ND+ firmware (I'm not sure how to draw the line between them) since the FileStream API allows for opening the same file multiple times (hence the FileShare enumeration). Removing the multithreading was the easiest way to get back to a working state until I could sort out whether I am supposed to be able to open a file multiple times.
What exactly is the shared resource in this case? Is it the file? Is it the entire SD card? Something else?
Locking based on individual files could be annoying to implement. Locking the whole SD card is easy - but less than ideal. If you widen the scope of the lock too much, you can defeat the purpose of multithreading.
Oh, and of course it crashed, you told people about it
Yeesssss! That is exactly what I'm looking for! I really wanted the processing to be done in Main and not the class itself, so this is perfect.
Here is my updated code with Cabadam's suggestion:
--snipped--
Thanks!
Glad it was what you were looking for. I would go back and make a local variable for your request to pass in. Again, it is an unlikely threading issue to run into it. But IF you do actually run into - it will be a royal P.I.T.A. to troubleshoot. So I'd add the extra one line and move on
I think I lost ya on that one... how would passing the original Request variable cause any threading issues?
Glad it was what you were looking for. I would go back and make a local variable for your request to pass in. Again, it is an unlikely threading issue to run into it. But IF you do actually run into - it will be a royal P.I.T.A. to troubleshoot. So I'd add the extra one line and move on
If you're talking about writing to a log file from multiple threads, just synchronize your write function...
[MethodImpl(MethodImplOptions.Synchronized)]
public static void Write(string message)
{
// Write to the log
}
I didn't mean to say it was impossible. To me it just sounded like I hit a bug in the framework and/or ND+ firmware (I'm not sure how to draw the line between them) since the FileStream API allows for opening the same file multiple times (hence the FileShare enumeration). Removing the multithreading was the easiest way to get back to a working state until I could sort out whether I am supposed to be able to open a file multiple times.
What exactly is the shared resource in this case? Is it the file? Is it the entire SD card? Something else?
Locking based on individual files could be annoying to implement. Locking the whole SD card is easy - but less than ideal. If you widen the scope of the lock too much, you can defeat the purpose of multithreading.
Oh, and of course it crashed, you told people about it
I think I lost ya on that one... how would passing the original Request variable cause any threading issues?
The issue is that you aren't actually passing the original request variable. You are passing an 'expression' (e.Request) that will not actually be evaluated until the thread starts (at which point your lambda gets invoked). THEORETICALLY, in the general case, some other thread could have access to your "e" object and alter the value of Request. Thus, when your thread starts, it would end up executing against the new value rather than the old.
But, if you instead create a local variable for the request - that cannot be modified by another thread, so you know you are always going to get the right value.
If you're talking about writing to a log file from multiple threads, just synchronize your write function...
[MethodImpl(MethodImplOptions.Synchronized)]
public static void Write(string message)
{
// Write to the log
}
Well, in this particular case it was reading from various files (to return via HTTP to the client). Unless it is simply a limitation of the micro framework, I'm not sure why multiple readers would not be able to access a file simultaneously.
I didn't mean to say it was impossible. To me it just sounded like I hit a bug in the framework and/or ND+ firmware (I'm not sure how to draw the line between them) since the FileStream API allows for opening the same file multiple times (hence the FileShare enumeration). Removing the multithreading was the easiest way to get back to a working state until I could sort out whether I am supposed to be able to open a file multiple times.
What exactly is the shared resource in this case? Is it the file? Is it the entire SD card? Something else?
Locking based on individual files could be annoying to implement. Locking the whole SD card is easy - but less than ideal. If you widen the scope of the lock too much, you can defeat the purpose of multithreading.
Oh, and of course it crashed, you told people about it public/style_emoticons/default/smile.gif
As I am only running VS2010 express, and I don't have the threads Window, debugging multithreaded is a bit harder.
When I said the "shared resource" I deliberately left it in general terms. For the case of the SD card I think the critical "resource" is the SPI bus. If one thread comes in over the top here then both messages will probably fail.
for example this is not going to work because multiple threads can access the spi bus.
[MethodImpl(MethodImplOptions.Synchronized)]
public static void WriteCard(string message)
{
// Write to the log
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static string ReadCard()
{
...
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static byte[] ReadTempViaSPI()
{
...
}
but something like this should, obviously only lock the smallest chunks possible, and trap any exceptions.
public class Test
{
private object _LockSPI = new object();
public void Write(string data)
{
lock ( _LockSPI )
{
}
}
public string Read()
{
lock ( _LockSPI )
{
}
}
public byte[] ReadSPIDevice()
{
lock ( _LockSPI )
{
}
}
Oh, and of course it crashed, you told people about it
I did test it via autorefresh before posting and did thousands of page requests over 6 days. <sigh>
I think I will have a second netduino be a watchdog for the online netduino.
Ahh, because of the lambda expression! I never really use them that much... thanks for the heads-up!
The issue is that you aren't actually passing the original request variable. You are passing an 'expression' (e.Request) that will not actually be evaluated until the thread starts (at which point your lambda gets invoked). THEORETICALLY, in the general case, some other thread could have access to your "e" object and alter the value of Request. Thus, when your thread starts, it would end up executing against the new value rather than the old.
But, if you instead create a local variable for the request - that cannot be modified by another thread, so you know you are always going to get the right value.
public class Test
{
[MethodImpl(MethodImplOptions.Synchronized)]
public void Write(string data)
{
...
}
[MethodImpl(MethodImplOptions.Synchronized)]
public string Read()
{
...
}
[MethodImpl(MethodImplOptions.Synchronized)]
public byte[] ReadSPIDevice()
{
...
}
}
Which approach you decide to take is up to you. The attribute approach will lock the whole method, where lock() can be used to only lock portions of a method.
Yes you're right.
Thanks Teets for pointing this out. ( note to self: read doco and dont make incorrect assumptions)
After reading the doco it seems that the synchronized attribute does Synchronize separate methods within the same class.
But a word of warning if your SD card functions were in a different class to your other SPI functions (which I think could be quite common) then they wouldn't be synchronized.
My preference is for the explicit lock syntax.