To thread or not to thread

Forum regarding Windows Software and Home Automation Domotica.
Post Reply
Digit
Global Moderator
Global Moderator
Posts: 3388
Joined: Sat Mar 25, 2006 10:23 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Digit »

Hi all,

This typically is a question to all of you who are also writing their own software to manage their Home automation. More of a question like "How do *you* cope with this?" than a real question about a problem i'm facing.

Let me explain.
As more and more physical interfaces are monitored, the question of reponsiveness began to arise.

The situation i was facing was the following:
I have a TI-213 to get all X10 data from the power line to my PC. But, if you're planning on switching lights on/off by means of X10 triggered by X10 motion, you'll need a rather fast polling rate. The quicker, the better i would say.

But, this becomes quite hard when one single process also has to deal with 1-Wire temperature sensors, where 1 temperature conversion can take more than 1 second to complete.
While waiting for this conversion to complete, the arriving X10 data is not serviced...this was not acceptable to me.

What i did to get rid of this 'delay', was to give every 'interface' it's own thread.
So, now i have one thread for receiving X10 data, one for 1-Wire, one for the ISDN Call monitor, one for generating Bar- and Line-charts of all data that is gathered, and so on.

As everyone who has worked with threads knows, they do have some side-effects. Maybe i would be better off with multiple processes all dealing with just one interface?
It would make programming much easier NOW, but what problems will i be facing in the future? I don't know.
I mean, all interfaces produce events, and will trigger actions as output going to other interfaces. So these processes would have to be able to communicate to each other.
Just another challenge perhaps...

Now, i don't think i'm the first starting my own Home automation 'thing'. How did *YOU* cope with this?

Regards,
Digit.
Bwired
Administrator
Administrator
Posts: 4704
Joined: Sat Mar 25, 2006 1:07 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Bwired »

Digit
Where are you programing in?
I still use VB6 (no threading) and I want to change over to VB.NET and ASP.NET.
Pieter
Digit
Global Moderator
Global Moderator
Posts: 3388
Joined: Sat Mar 25, 2006 10:23 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Digit »

Pieter,

Currently i'm using Delphi 2005, still only Win32 stuff, no .NET. Yet...
Thought about switching to VS .NET 2005, but i think i'll have to rewrite too much.....

I did some small things like a VCR Scheduler for my TV-tuner in the VB Express-version, was pleasantly surprised by how fast you could do things with it, but still, starting all over again...i don't know yet.

Regards,
Robert.
Bwired
Administrator
Administrator
Posts: 4704
Joined: Sat Mar 25, 2006 1:07 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Bwired »

Hi Robert,
Yes the Studio 2005 is a powerful tool, I was lucky to get a free license of Microsoft including SQLserver 2005. I'm planning to move over specially the integration with ASP.NET 2.0 is very good. Also new techniques line AJAX where you don't have to refresh your screen anymore and only the data changes, is very powerful. Did some testing and I loved it.
Back to multi threading, as I was telling you I use VB6 for my Home Automation system. I have about 8 RS232 interfaces and I really don;t have a problem with handling them all (sequentially). I have however a little function which I can call for example from within a loop and tell the loop to go to sleep for a little time to other processes can be handled. Looks like this:

If (Y Mod 10) = 0 Then (Y is the loop counter)
DoEvents (or sleep function)
End If

I must say my program is very fast and all is handled good, even in debug mode which I usually run in.
Pieter
bjorn
Starting Member
Starting Member
Posts: 13
Joined: Wed Nov 29, 2006 10:56 am
Location: Finland

To thread or not to thread

Post by bjorn »

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote"><i>Originally posted by Digit</i>
<br />
But, this becomes quite hard when one single process also has to deal with 1-Wire temperature sensors, where 1 temperature conversion can take more than 1 second to complete.
While waiting for this conversion to complete, the arriving X10 data is not serviced...this was not acceptable to me.

What i did to get rid of this 'delay', was to give every 'interface' it's own thread.
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">Threading does not give you any more speed unless you are using multiple processors, a multicore processor, or hyperthreading. On a "normal" unicore processor theading just changes the way of programming. The key is to never busy loop. To get the most out of your processor, use asynchronous OS calls where possible and do other stuff while the OS is waiting to complete I/O.

Taking your 1-wire temperature reading problem as an example. You could send the convert temperature command (which doesn't take much over a millisecond) and go on polling your X10 devices. After 750ms you can get back to your 1-wire and read the temperature, which again is very fast. If you are eager to get the temperature faster than the maximum convertion time you can every now and then read a single bit from the 1-wire to see if convertion is ready (assuming you are not using parasite power). This is however probably a useless optimization, I can't see why one would want the temperature faster than a second in a home automation system.

Anyway, I promise you, you want miss a single event on from the X10 system when using 1-wire devices and a single process with a single thread. Just don't busy loop.
Bwired
Administrator
Administrator
Posts: 4704
Joined: Sat Mar 25, 2006 1:07 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Bwired »

Hi
Bjorn you are right about threading! I have a Dual P4 XEON machine with hyperthreading so Windows sees 4 XEON processors.

Question for Digit is: With what device to you read the 1-Wire bus, I do it with the LOG08 from Midon http://www.midondesign.com , which is standalone device (1-Wire recorder) that is for example scanning the bus every 1 minute, the data is then in the internal memory of the log08, once every I read the internal memory of the log08 which is very fast. I can see that the log08 needs more time scan the bus. If you have a direct RS232 1-wire reader it could take much longer.
Regards Pieter

Pieter Knuvers
www.bwired.nl Online House in the netherlands. Domotica, Home Automation.
Digit
Global Moderator
Global Moderator
Posts: 3388
Joined: Sat Mar 25, 2006 10:23 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Digit »

@Bjorn:

I know what threading does and does not do. I'm not doing threading for more speed. I'm on an average of 0.3% CPU (AMD 2400) right now, so that's not going to be a problem.

And yes, i'm using parasite power on the 1-Wire bus. The routine i am using to read the temperature has a 1-second loop to wait for the conversion to complete (as you seem to be familiar with 1-Wire: taken from tempdl32, Dallas SDK). I chose not to alter this routine too much (as in "don't try to fix it when it's not broken" :-)).

And i know, i won't miss any X10 events by this 1-second loop/delay, but what if these X10 events should trigger something else ASAP, for example a lamp being switched on by detected motion? Then 1 second delay will feel like 3...

Of course, it wouldn't be too hard to do "other things" while in this temp-conversion-waiting-loop: some sort of queue for not-so time critical jobs is something that has already been incorporated, for things like creating chart images and things like that. But now i was facing the fact of a blocking 1-Wire routine and a X10 query that i didn't want to be influenced by that.
In fact, i was at a point where you have to ask yourself whether you keep adding code to keep things responding fast enough or let the OS help you doing this.

And since i regarded the 1-Wire temp conversion as one single procedure, i had to find a way to do these 'other things' simultaneously rather than 'in between'. So that would mean dedicating a seperate thread to each physical interface. It's just a matter of personal feeling i think, my refusal to split the 1-Wire temp conversion into separate parts, or in fact, adding a sophisticated 'goto'. In fact, i'm now letting the OS do the 'goto' for me.

So for now, the loop is still there and i've had to deal with it in some way. And from what i've learned so far, threading is a solution to consider. And i was just wondering if anyone else encountered the same kind of challenges and how they were solved.

Just this weekend i came across another example where threading comes in very handy. Working on a CAPI Call Monitor this weekend, i found there are basically 2 ways to get notified of an incoming call:
1. Polling a GetMessage(), say twice a second and see if an incoming call is in progress, or
2. call a WaitforSignal() routine once and just sit and wait for returning from it.

I decided to choose option 2. Why poll when you can wait for something to announce itself? Yes, normally option 2 would freeze my whole application. But not when i would dedicate a thread to it. I did, and it works great.

@BWired:

I think you already know the answer, i'm not using a device like the LOG08, i'm doing everything with a Dallas DS9097U. That's why i'm probably facing issues you don't.

In general, i think feeling the need for threading is something that is inherent of "thinking OOP".

Regards,
Robert.
MindBender
Advanced Member
Advanced Member
Posts: 640
Joined: Sun Apr 30, 2006 5:31 pm
Location: Netherlands
Contact:

To thread or not to thread

Post by MindBender »

Hello Digit,

The solution to your problem may lay in cooperative multi tasking; This is very frequently used in embedded software where multiple tasks must be executed, but where the hardware is too light to use a full scale operating system. Basically you execute all functionality in one thread, but nobody is claiming the processor for a long time, especially not for 'waiting'. Below I have typed a small example, where I also show how you can make objects in any programming language. This example is in C, but I'm sure you can read it anyway.
By the way: Why don't you learn a <i>decent</i> language? Deplhi is for kidz and don't get me started about VB. [:p]

Pieter: I've been typing this post twice!! After pasword authentication fails, it doesn't retain the typed text in the box. I've had this very frequentley and it's <b>VERY ANOYING</b>.

<font face="Courier New">

Code: Select all

/************************************************************/
/* Main.c
/************************************************************/

void main (void)
{
        void*   I2C_object = 0;
        void*   1Wire_object = 0;
        void*   ..._object = 0;
        int     exit = 0;

        I2C_object   = init_I2C();
        iWire_object = init_1Wire();
        init_...     = ..._init();

        do {
                do_I2C(I2C_object);
                do_1Wire(1Wire_object);
                do_...(..._object);
        } while(!exit)
        
        term_...(..._object)
        term_1wire(1Wire_object);
        term_I2C(I2C_object);
}

/************************************************************/
/* I2C.c
/************************************************************/

typedef enum {
        idle = 0,
        transmit,
        transmitting
        /* Other states go here */
} I2C_enum;

typedef struct {
        I2C_enum        state ;
        /* Other properties go here */
} I2C_struct;


void* init_I2C(void)
{
        /* Initialize hardware, set global properties */
        /* Put your global properties is a struct: This */
        /* is the place to malloc memory for this struct. */
        /* In that case the address of the struct should be */
        /* returned and used as 'object handle' in every */
        /* function call. */
        \
        I2C_struct* addr = malloc(sizeof(I2C_struct));

        if (addr){
                addr->state = idle ;
                /* Other properties initialized here */
        }

        return ((void*)addr);
}

void do_I2C(void* object)
{
        switch(object->state) {
        case idle:
                /* Do nothing */
                break;
        case transmit:
                /* Copy message to transmit buffer */
                object->state++;
                break;
        case transmitting:
                /* Wait for transmit buffer to clear */
                if (txbuffer(object)==0)
                        object->state = idle;
        default:
                break;
        }
}

void term_I2C(void* object)
{
        free(object);
}

int transmit_I2C (void* object, unsigned char address, unsigned char * data, int length)
{
        /* Check if busy */
        if (object->state != idle)
                return (-1);

        ....
        
        return(0);
}
</font id="Courier New">
bjorn
Starting Member
Starting Member
Posts: 13
Joined: Wed Nov 29, 2006 10:56 am
Location: Finland

To thread or not to thread

Post by bjorn »

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote"><i>Originally posted by Digit</i>
<br />
And yes, i'm using parasite power on the 1-Wire bus. The routine i am using to read the temperature has a 1-second loop to wait for the conversion to complete (as you seem to be familiar with 1-Wire: taken from tempdl32, Dallas SDK). I chose not to alter this routine too much (as in "don't try to fix it when it's not broken" :-)).
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

Ok, I didn't realize you were using the SDK. I am not very familiar with the SDK, but isn't there a routing to send any 1-wire command? Then you could send the "convert temperature" command, do some other stuff, poll the X10 devices, and then one second later send the "read scratchpad" command.

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote">
And i know, i won't miss any X10 events by this 1-second loop/delay, but what if these X10 events should trigger something else ASAP, for example a lamp being switched on by detected motion? Then 1 second delay will feel like 3...
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

I meant that if you operated as suggested above, not using the blocking SDK routine, then you would not have the 1 second delay, but delays in the range of milliseconds. I understand that a 1s blocking routing is too long.

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote">
And since i regarded the 1-Wire temp conversion as one single procedure, i had to find a way to do these 'other things' simultaneously rather than 'in between'. So that would mean dedicating a seperate thread to each physical interface. It's just a matter of personal feeling i think, my refusal to split the 1-Wire temp conversion into separate parts, or in fact, adding a sophisticated 'goto'. In fact, i'm now letting the OS do the 'goto' for me.
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

Ok, I understand.

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote">
So for now, the loop is still there and i've had to deal with it in some way. And from what i've learned so far, threading is a solution to consider. And i was just wondering if anyone else encountered the same kind of challenges and how they were solved.
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

I am also intermixing 1-wire devices and other home automation devices. I have written all the 1-wire stuff myself so I don't have the 1 sec delay problem. For the higher level stuff I am using Python and the Twisted Matrix framework, http://twistedmatrix.com/. This framwork is build around the concept of only asynchronous and non-blocking calls in a single threaded application. This gives you a threaded feeling in a single threaded application which I like (since I, like you, don't need threads for more computational power). As you stated, threads have their own problems and can get fairly complex if you are not careful.
bjorn
Starting Member
Starting Member
Posts: 13
Joined: Wed Nov 29, 2006 10:56 am
Location: Finland

To thread or not to thread

Post by bjorn »

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote"><i>Originally posted by Bwired</i>
<br />If you have a direct RS232 1-wire reader it could take much longer.
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

Don't know the overhead of Windows, but without this overhead it does not take many milliseconds to read the temperature even if you writing and reading every single bit with for example a RS232 1-wire reader.

I send the "skip rom" and "convert temperature" commands so that all temperature devices do the convertion at the same time. This way I don't have to address every device individually for the convertion. Then I wait a second (or alternatively by polling for a "1" bit on the 1-wire bus meaning that all devices have converted). Then after this I can read the temperature for each device individually. Even if I have 50 devices it does not take very long, independently of what reader is used.
Digit
Global Moderator
Global Moderator
Posts: 3388
Joined: Sat Mar 25, 2006 10:23 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Digit »

Hello MindBender,

Thanks for your reply! It made old memories come back...
In fact the solution you mentioned is something i used once, almost 15 years ago, in a project where i made an installation for doing efficiency-calculations on central heatings. (CV's).
It involved gas-pressure-, gas-temperature-, watertemperature- and flow-measurements, PID calculations, 3-way valve adjustments, graphical display of it all and it was all done just the way you described...
Completely forgotten that approach, didn't even know there was a name for it.

Since then i moved (in my profession) to a different area where only database-I/O is what i have to deal with, actually no other processes to worry about, so this experience was 'lost' in a way.

I think i can go 2 ways now. Splitting up the 1-Wire temp-conversion into smaller parts to get rid of the waits so i can use time more efficiently, or stick with threads.
Don't know 100% what it's gonna be yet, but i think it's gonna be a rewrite of the SDK samples since that won't be too hard to do.

But, another thing that passed my mind the last few days is that, no matter what i do with the 1-Wire temp-conversion, eventually i think i'll have to resort to threading anyway, since i've written some routines to create charts of all data that's coming in. They're executed periodically to produce charts for the web interface. Making those routines cooperative would probably be a bit more complex, since there's a bit more involved here than just 1 database query and creating an image of it.

So i think, eventually, it's gonna be a mix of both worlds...

Regards,
Robert.
Digit
Global Moderator
Global Moderator
Posts: 3388
Joined: Sat Mar 25, 2006 10:23 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Digit »

Hello Bjorn,

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote"><i>Originally posted by bjorn</i>
<br />
Ok, I didn't realize you were using the SDK. I am not very familiar with the SDK, but isn't there a routing to send any 1-wire command?
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

Well, actually the examples in the SDK are routines like : "Read the temperature" or "read a DS2423 counter value".

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote">
I meant that if you operated as suggested above, not using the blocking SDK routine, then you would not have the 1 second delay, but delays in the range of milliseconds. I understand that a 1s blocking routing is too long.
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

Ok, clear.

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote">
I have written all the 1-wire stuff myself so I don't have the 1 sec delay problem.
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">
Well, maybe that's the source of the problem; i haven't. I used the examples from the SDK and probably regarded them as 'finished' too much.

Thanx for your ideas!

Regards,
Robert.
Digit
Global Moderator
Global Moderator
Posts: 3388
Joined: Sat Mar 25, 2006 10:23 am
Location: Netherlands
Contact:

To thread or not to thread

Post by Digit »

Hello Bjorn,

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote">
Don't know the overhead of Windows, but without this overhead it does not take many milliseconds to read the temperature even if you writing and reading every single bit with for example a RS232 1-wire reader.
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

I think you are right about that. Till now i haven't found RS232 to be a bottleneck for the speed in which i'd like to see results coming in; whether it's 1-Wire or X10.

Regards,
Robert.
User avatar
Willem4ever
Global Moderator
Global Moderator
Posts: 805
Joined: Mon Oct 30, 2006 3:48 pm
Location: Uithoorn / Netherlands

To thread or not to thread

Post by Willem4ever »

<blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote"><i>Originally posted by Digit</i>
<br />Hello MindBender,

Thanks for your reply! It made old memories come back...
In fact the solution you mentioned is something i used once, almost 15 years ago, in a project where i made an installation for doing efficiency-calculations on central heatings. (CV's).
It involved gas-pressure-, gas-temperature-, watertemperature- and flow-measurements, PID calculations, 3-way valve adjustments, graphical display of it all and it was all done just the way you described...
Completely forgotten that approach, didn't even know there was a name for it.

Since then i moved (in my profession) to a different area where only database-I/O is what i have to deal with, actually no other processes to worry about, so this experience was 'lost' in a way.

I think i can go 2 ways now. Splitting up the 1-Wire temp-conversion into smaller parts to get rid of the waits so i can use time more efficiently, or stick with threads.
Don't know 100% what it's gonna be yet, but i think it's gonna be a rewrite of the SDK samples since that won't be too hard to do.

But, another thing that passed my mind the last few days is that, no matter what i do with the 1-Wire temp-conversion, eventually i think i'll have to resort to threading anyway, since i've written some routines to create charts of all data that's coming in. They're executed periodically to produce charts for the web interface. Making those routines cooperative would probably be a bit more complex, since there's a bit more involved here than just 1 database query and creating an image of it.

So i think, eventually, it's gonna be a mix of both worlds...

Regards,
Robert.
<hr height="1" noshade id="quote"></font id="quote"></blockquote id="quote">

Hi Digit,

There is nothing wrong with threading, over 20 years ago in the days of CP/M i created my first multi-tasking apps. using iRMX/86 (in the days that small computers cost > E 50.000,- or more). Why create your own schedulers if the OS can do it for you ... However you have to be more carefull about your stack usage ... You have to use semaphores too avoid different threads trying to write the same memory location etc etc. It also more difficult to debug, but at the end you program it easier and better to understand by other people. Again you as the developer have to weigh the pros versus the cons using one technique or the other.

Cheers,
Willem.
Post Reply

Return to “Windows Forum”