Why Threading?

But... do you really need it?

Just from the moment I began to plan my “networking component” implementation, the warning of Benoît “do not use threads!” was planning over me like a nightmare.

If I wanted to inform the main application that anything was happening in the socket, I had to raise an event from the main thread, no way to do it asynchronously, so it seems that if main application does not use any method or property from the component, I could not call any function from my component to look if there was data avilable, or any other change in the socket.

FIRST APPROACH

Main application --> Calls method X of component ---> X checks if there's any change, and then raises an event if necessary.

This is a very poor implementation, as if main application does not care continuosly for socket state, that application can not really know what's happening in “real world”.

But, when there's a well-designed API, as Gambas programming interface is, nightmares become sweet dreams. There's a method called GB.Watch used to tell Gambas runtime that it has to look if something has happen in a file descriptor, and inform the component of this using a Call-Back.

As Linux and other UNIXes are also well designed systems, almost everything is a file descriptor (files, folders, hardware, sockets, pipes...) so you can be informed in your component of the whole world ir “real-time” without any help from the programmer of the main application. In this case, I just turn the socket descriptor asynchronous (to avoid blockings when connecting or reading), tell Gambas that is has to care about that file descriptor, and raise an event when my call-back is called by Gambas runtime.

SECOND APPROACH

Gambas Runtime --> Component CallBack --> Event --> Main application

So, the conclusion is that, in 90% of component programming you'll have not to enter in the unstable world of threading programming. This is true not only for Gambas: unless you have to program for machines with two or more CPUs, or manage two or more task in real-time, you rarely will be forced to use threads. In fact, threading does not increase program speed, as CPU has to manage more tasks, changing from one to other if short intervals of time.

So... do you really need it?

Well, not always the (operating) system is going to help us. In this component, for example, there are two calls that blocks the main thread for a unknown elapse of time:

gethostbyname()

gethostbyaddr()

When calling a DNS server, it can reply to the request quickly, slowly... or never respond, and the main application can't do anything in that time.

This seems to be a good oportunity to let the threads appear in scene.

First of all : Clear your mind

Are you sure you can not do it without threads? Thread programming is difficult, dangerous for applications stability if not well-designed, a hell to debug... think it twice before starting that work.

We have to keep in mind some concepts:

1º) You can not use all usual programming resources from a thread: in that example, you can not really call to gethostbyname() or gethostbyaddr(), as they were not designed to be “reentrant”, this is, calling them from various threads can hang the program. In fact, you have to use “reentrant” versions of these methods: reentrant version of gethostbyname(), called gethostbyname_r(), and reentrant version of gethostbyaddr() called gethostbyaddr_r().

2º) Never call Gambas API from a thread, it was not designed to be used by multiple threads.

3º) Be carefull using resources, remember to use semaphores or mutex when a resource (memory, files...) could be accesed by two or more threads (including main thread!) at the same time.

Second : But what about events?

Well, we have a thread but we can not raise events... mmmh.... but you can do it from the main thread!

I had this idea due to my previous experience with ActiveX components. One of our costumers needed a very fluid human interface, so we could not stop main thread more than one second. I began to program a multithreated ActiveX component and I found a hard problem. Each time I tried to raise an event from the thread the program failed with a segmentation fault. I had to investigate in internet, and finally I found a document explaining that COM interfaces do not allow to do such a thing, but there was a way to avoid this problem. To explain it briefly, you have to create an invisible window at main thread, then pass its handle to the thread, and the thread will send a message to that window by using “sendmessage”. At the windows, this message is managed by a function which raises the event (now, in main thread, on event loop).

Well, the idea for Gambas is similar, but do not care, you have not to create an invisible window.

As I said previously, GB.Watch allows us to watch for a file descriptor, so:

1º) Create a pipe from the main thread, it will create two file descriptors : one for reading, and the other for writing.

2º) Create your thread, by passing it the write descriptor.

3º) At main thread, use GB.Watch to associate the thread descriptor with a call-back, using GB_WATCH_READ flag.

4º) When you need to inform of something, send some data by the write-descriptor (this data can be any key to specify the main thread what to do)

5º) The main thread will notify the component using the call-back, that there's data available at read descriptor, so, in call-back implementation you can read that data and raise an event if neccessary, or modify values of properties.

That's all. I think creating a pipe wastes less resources than creating an invisible window, don't you? Unix things...

You can look the thread example at CDnsClient.c and CdnsClient.h

2003-09-13T21:51:42