At work, I'm trying to run the same filter multiple times. (Run the same
filter 5 times for 5 files or later for 5 sensors).
My idea was to create a seperate thread that run the same filter for each
input. This filter is an ANSI C part wich contains some global functions.
Should it be possible to execute these 5 threads completely independently or
are there some conditions to this. (Are global (shared) functions a
problem?)
Thank you in advance
Patrick Riphagen
Not the functions I guess, but if they do use any "static" data (like
buffers). Eg:
This is problem:
const char *gimmeString( int which) {
char stringOf[4000];
fillString( &stringOf, which);
return stringOf;
}
This is not a problem:
int gimmeString( char *target, size_t buffsize, int which) {
int success=1;
// Here is the work
return success;
}
A
Thanks, but I'm not using any globals or statics (exept the functions, which
are included in the Class)
I used to do this but I converted them to local variables. Still if I run
the threads at the same time, the results defer slightly ( 10EXP-5 order)
They seem to be interfering, but there not using each others variables for
as far as I can see, any more suggestions on how they can be using some
shared memory or something like that?
Patrick
"Attila Feher" <Attila...@lmf.ericsson.se> wrote in message news:3B822C5C...@lmf.ericsson.se...
> Patrick Riphagen wrote:
> >
> > Hello all,
> >
> > At work, I'm trying to run the same filter multiple times. (Run the same
> > filter 5 times for 5 files or later for 5 sensors).
> > My idea was to create a seperate thread that run the same filter for each
> > input. This filter is an ANSI C part wich contains some global functions.
> > Should it be possible to execute these 5 threads completely independently or
> > are there some conditions to this. (Are global (shared) functions a
> > problem?)
>
> Not the functions I guess, but if they do use any "static" data (like
> buffers). Eg:
>
> This is problem:
>
> const char *gimmeString( int which) {
> char stringOf[4000];
> fillString( &stringOf, which);
> return stringOf;
> }
>
This is a problem only because you return a pointer into the stack. It won't work
reguardless of threading ;)
This won't work in multiple threads:
const char *gimmeString( int which ) {
static char stringOf[4000];
fillString( stringOf, which);
return stringOf;
}
because the stringOf buffer is static, all threads see the same one.
> This is not a problem:
>
> int gimmeString( char *target, size_t buffsize, int which) {
> int success=1;
> // Here is the work
> return success;
> }
>
> A
Global functions are all right, global data is not. Check the filter code to make sure there
are no globally declared variables, including static declarations inside functions.
You _can_ use global variables, just protect access to them with a mutex or critical section.
Dan
>
> Global functions are all right, global data is not. Check the filter code
to make sure there
> are no globally declared variables, including static declarations inside
functions.
> You _can_ use global variables, just protect access to them with a mutex
or critical section.
>
I'd like to use global variables, but they should be global for 1 thread,
not global for the entire app.
So I need some kind of "thread-globals". Is there a way of accomplishing
this?
Now I pass all formely global variables as function arguments within each
thread, but I'm not really fond of this solution, other possibilities?
Patrick
There are platform-specific ways to associate objects with threads. Under
POSIX, you have the functions pthread_key_create, pthread_key_destroy,
pthread_getspecific and pthread_setspecific.
There is nothing comparable under Win32. The TlsAlloc function and related
functions look superficially similar but they lead to memory leaks,
because there is no way to associate a destructor with a thread-specific
object which is called when the thread terminates. (But if you are writing
a DLL, you can hook this destruction to the DllMain(DLL_THREAD_DETACH)
call).
The Microserfs clearly didn't read the POSIX documentation carefully
enough before they cloned the functionality. ;)
>Now I pass all formely global variables as function arguments within each
>thread, but I'm not really fond of this solution, other possibilities?
The real solution to this are dynamically scoped variables, in languages
like Lisp. In fact, this is such a useful language feature, that it's worth
emulating.
Briefly, a dynamically scoped variable is one whose reference is resolved
by considering the activation chain in which the reference is made.
The variable can be bound somewhere in the activation chain; if it isn't,
then a global value is retrieved. (Under threads, that global value
should be thread-specific).
The dynamic resolution means that a function can redefine a local version
of the variable before calling another function. That called function
will then access the local version rather than the global one; effectively
the local binding shadows the global one.
If C had dynamically scoped variables, it would look something like this:
#include <stdio.h>
int x = 3; /* global one */
void foo()
{
printf("x = %d\n", x);
}
void bar()
{
dynamic int x = 4; /* fictitious keyword, ``dynamic'' */
foo(); /* foo will now print 4, not 3 */
}
int main(void)
{
foo(); /* foo will print 3 */
bar();
return 0;
}
So, effectively, the behavior is as if you were passing the entire set
of dynamic variables into every function, allowing you to pass down
arbitrary state information, without having to explicitly do so
in the argument list. It's a kind of taming of global variables.
> Now I pass all formely global variables as function arguments within each
> thread, but I'm not really fond of this solution, other possibilities?
Why aren't you fond of it? This is really what you mean, isn't it?
DS
P
--
Arnold Hendriks <a.hen...@b-lex.com>
B-Lex Information Technologies, http://www.b-lex.com/
Chris
No. It's terrible. The idea of passing parameters in global variables is
fundamentally bad. It makes the software gratuitously difficult to
understand, by making it very difficult to track down all the places
where they are updated and used. This is what scoping rules are
intended to facilitate.
Even if there was no other reason to avoid the technique, it is quite
possible that access to thread-specific storage is less efficient
than any other type of access, and it is highly likely that it is
less efficient than access to ordinary parameters. For example, on
the SPARC processor, parameters are passed in registers, so even if
thread-specific storage is implemented by allocating a global
register to point to the thread-specific storage area, loading and
storing each value will take extra memory accesses.
--
Eppur si muove
without TSD:
A( thread_name ) // A does not need thread_name; calls B
B( thread_name ) // B does not need thread_name; calls C
C( thread_name ) // C does not need thread_name; calls D
.
.
.
Z( thread_name ) {
// lock resource X
...
// trace/log thread_name, X, "work_beg", time
...
// do some work using locked resource X
...
// trace/log thread_name, X, "work_end", time
...
// unlock resources X
...
}
with TSD:
static tsd_key thread_name_key;
A( thread_name ) // A saves thread_name and calls B
// without thread_name arg
once_init( &thread_name_key )
tsd_set( thread_name_key,thread_name )
B() // B calls C without thread_name arg
C() // C calls D without thread_name arg
.
.
.
Z() {
thread_name = tsd_get( thread_name_key );
// lock resources X
...
// trace/log thread_name, X, "work_beg", time
...
// do some work using locked resource X
...
// trace/log thread_name, X, "work_end", time
...
// unlock resources X
...
}
regards,
alexander.
I'm not entirely sure what point you are trying to make, but I think
this is a classic abuse of thread-specific data. It seems to arise
from a fundamental misconception about what threads should be: they
are not objects - they act on objects, so a program shouldn't care
which thread does an item of work, so it should have no need to know
which thread is running at any point. Obviously test and debugging
doesn't follow this rule, just as it doesn't follow any other rules
for good design.
--
Eppur si muove
What precisely are proper uses of TSD? When is its use called for and when
is it not?
Thank you,
Marc
It's most important use is the implementation of misdesigned
interfaces which cannot be changed. For example, the really bad
strtok() which saves an argument you pass in and re-uses it at
subsequent calls. Another well-known example is the implementation of
errno, which obviously must be different in each thread. While the
loss of strtok() would be quite beneficial, errno is just too deeply
entrenched to get eliminated.
--
Eppur si muove