Netduino home hardware projects downloads community

Jump to content


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.
Photo

No ParameterizedThreadStart


  • Please log in to reply
18 replies to this topic

#1 Teets

Teets

    Member

  • Members
  • PipPip
  • 16 posts

Posted 02 February 2012 - 04:21 AM

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)
{
    ...
}

Any ideas?

- NICK

#2 Magpie

Magpie

    Advanced Member

  • Members
  • PipPipPip
  • 279 posts
  • LocationAustralia (south island)

Posted 02 February 2012 - 10:42 AM

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();
        }
    }
}

STEFF Shield High Powered Led Driver shield.

#3 Teets

Teets

    Member

  • Members
  • PipPip
  • 16 posts

Posted 18 February 2012 - 01:58 AM

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();
        }
    }
}



#4 Teets

Teets

    Member

  • Members
  • PipPip
  • 16 posts

Posted 21 February 2012 - 03:28 PM

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
    }
}


I hope this helps someone else!

#5 Cabadam

Cabadam

    Advanced Member

  • Members
  • PipPipPip
  • 90 posts

Posted 24 February 2012 - 11:14 PM

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)
{
    ...
}


#6 Chris Seto

Chris Seto

    Advanced Member

  • Members
  • PipPipPip
  • 405 posts

Posted 24 February 2012 - 11:53 PM

Wow, this is spooky, I was doing this exact same thing today. I take it you guys are all trying multithreaded webservers?

#7 Cabadam

Cabadam

    Advanced Member

  • Members
  • PipPipPip
  • 90 posts

Posted 25 February 2012 - 12:00 AM

I was, but had to disable it since opening the same file on sdcard twice (even specifying fileshare.read) throws an exception.

#8 Magpie

Magpie

    Advanced Member

  • Members
  • PipPipPip
  • 279 posts
  • LocationAustralia (south island)

Posted 25 February 2012 - 12:59 AM

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.

temperature logger

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,

Edited by Magpie, 25 February 2012 - 03:53 AM.

STEFF Shield High Powered Led Driver shield.

#9 Teets

Teets

    Member

  • Members
  • PipPip
  • 16 posts

Posted 27 February 2012 - 03:02 AM

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).



#10 Cabadam

Cabadam

    Advanced Member

  • Members
  • PipPipPip
  • 90 posts

Posted 28 February 2012 - 12:43 AM

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.

temperature logger

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 :)

#11 Cabadam

Cabadam

    Advanced Member

  • Members
  • PipPipPip
  • 90 posts

Posted 28 February 2012 - 12:47 AM

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 :)

#12 Teets

Teets

    Member

  • Members
  • PipPip
  • 16 posts

Posted 28 February 2012 - 01:41 AM

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 :)



#13 Teets

Teets

    Member

  • Members
  • PipPip
  • 16 posts

Posted 28 February 2012 - 01:48 AM

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 :)



#14 Cabadam

Cabadam

    Advanced Member

  • Members
  • PipPipPip
  • 90 posts

Posted 28 February 2012 - 02:40 AM

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.

The problem can also show up if you are dealing with loops. There is an example of this: http://stackoverflow...-when-you-think

#15 Cabadam

Cabadam

    Advanced Member

  • Members
  • PipPipPip
  • 90 posts

Posted 28 February 2012 - 02:42 AM

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.

#16 Magpie

Magpie

    Advanced Member

  • Members
  • PipPipPip
  • 279 posts
  • LocationAustralia (south island)

Posted 28 February 2012 - 03:23 AM

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.
STEFF Shield High Powered Led Driver shield.

#17 Teets

Teets

    Member

  • Members
  • PipPip
  • 16 posts

Posted 28 February 2012 - 04:08 PM

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.

The problem can also show up if you are dealing with loops. There is an example of this: http://stackoverflow...-when-you-think



#18 Teets

Teets

    Member

  • Members
  • PipPip
  • 16 posts

Posted 28 February 2012 - 04:12 PM

Magpie, it should work in your context:

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.

#19 Magpie

Magpie

    Advanced Member

  • Members
  • PipPipPip
  • 279 posts
  • LocationAustralia (south island)

Posted 28 February 2012 - 10:27 PM

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.
STEFF Shield High Powered Led Driver shield.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.