3

I am trying to give each thread some thread-specific data; can this be done using the thread parameter?

So when creating the thread, I pass a variable, and in the thread function, I change its value and use it as a specific data for each thread?

int main(void){
    ...
    int Tparam = 0;
    ...
    rc = pthread_create(&threads[c1], NULL, Thread_Pool, (void *)Tparam);
    ...
}

then in the Thread_Pool function I use it like this

void *Thread_Pool(void *param){
    int id;
    id = (int) param;
    id = value; // can this value be a specific value for this thread?
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
CodeRed
  • 127
  • 3
  • 9
  • pthread_keycreate etc. Read doc. – bmargulies May 05 '12 at 19:57
  • 3
    Why don't you simply use thread local variables, using the __thread prefix? Such as __thread int tl_var; Secondly, you can't write to a null pointer as it points to location 0 which is write protected! You'll get a segmentation fault if you try to do this. – MetallicPriest May 05 '12 at 19:57
  • @bmargulies I read the pthread_keycreate, i was just wondering if this would work cuz i think its easier, and thanx for your answer. – CodeRed May 05 '12 at 20:04
  • @MetallicPriest I will read about the __thread prefix, i dont know it. Thanx for your suggestion :). – CodeRed May 05 '12 at 20:05
  • 3
    __thread is a windows crock. Not going to help with pthreads. – bmargulies May 05 '12 at 20:06
  • bmargulies: No, its also used in gcc, http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Thread-Local.html – MetallicPriest May 05 '12 at 20:12
  • GCC 3.3.1 is geriatric ... antique even. Can you quote a 4.x version instead? – Jonathan Leffler May 05 '12 at 20:16
  • @JonathanLeffler Thank you for your edit and well explained answer. – CodeRed May 05 '12 at 20:21
  • @bmargulies, it is `__declspec(thread)` in Windows. `__thread` is specific to GNU, Intel and Oracle compilers (and possibly IBM and PGI) on Linux and to C++Builder on Windows. – Hristo Iliev May 05 '12 at 21:44

4 Answers4

4

It might help if you showed how Tparam was declared.

However, if you want each thread to have its own space in which to store some data, then you can arrange to pass that space into the thread as the argument to the function. For example:

enum { NTHREADS = 10 };

struct TLS_Data
{
    int   id;
    char  buffer[2048];
    size_t index;
} data[NTHREADS];

for (int c1 = 0; c < NTHREADS; c1++)
{
    data[c1].index = c1;
    data[c1].id = 0;
    data[c1].buffer[0] = '\0';
    int rc = pthread_create(&threads[c1], NULL, Thread_Pool, &data[c1]);
    ...handle errors, etc...
}

Note the absence of a cast on the last argument to pthread_create(); it isn't necessary to convert a pointer to void * when there's a prototype in scope.

In your Thread_Pool, you seem to want to treat the parameter as an integer; that can be done too. It is most cleanly done passing a pointer to the integer; you can pass the integer value directly if you really insist:

uintptr_t value = c1 + 10;

rc = pthread_create(&threads[c1], NULL, Thread_Pool, (void *)value);

Because the type of value is uintptr_t, you know it is capable of holding a void pointer, and so it gives you the maximum chance of things working. But you're fighting the type system, which makes it harder to write clean code.

The one thing to be aware of is that you need to ensure that the data passed to the thread function (Thread_Pool() in your example) is not shared between threads if they are supposed to see different values. There is no guarantee of the order of thread execution, so if you made a mistake such as:

uintptr_t value = c1 + 10;

rc = pthread_create(&threads[c1], NULL, Thread_Pool, &value);

(and that code was in a loop), then there'd be no guarantee about what each thread function would see. Be cautious!

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
2

can this value be a specific value for this thread ?

Well, first thing's first, you probably want this:

int id = *((int*) param);

i.e. you need to dereference the parameter pointer after giving it a pointer with a type. You cannot dereference a void pointer, because void has no type.

Now - what happens here? Well, first we need to understand threads a bit.

Firstly - there is no distinction between a thread and a process in the kernel in Linux. Absolutely none. They're all contexts of execution, or tasks. However, one major difference is that threaded tasks share data - except for thread stacks. Reading that answer, you can see that a thread shares almost everything else with its creator.

A stack, however, must not be shared. Stacks track a number of things, for example where the program is up to execution-wise, return values and function parameters on some systems. Automatic storage duration variables - those without any other modifier - declared inside a function are also stored on the stack.

Which means - variables declared inside your thread function are unique to that thread. So, given your function:

void threadfunc(void* param)
{
    int id = /* ??? */
}

Each thread has its own copy of int id stored locally that will last for the duration of the thread. You can pass this to subsequent functions by value, or a pointer to it.

As such, it is perfectly valid to call:

int tParam[] = {1,2,3};

rc = pthread_create(&threads[0], NULL, Thread_Pool, (void *)&(tParam[0]));
rc = pthread_create(&threads[1], NULL, Thread_Pool, (void *)&(tParam[1]));
rc = pthread_create(&threads[2], NULL, Thread_Pool, (void *)&(tParam[2]));

and so on.

  • He is not dereferencing a pointer. He passes an integer disguised as a pointer and then casts that pointer back to interger. This is a pretty often used concept in POSIX threads since passing an automatic integer variable by address might lead to a runtime error if the thread starts after the creation function has exited and the automatic variable has been destroyed (which might happen in your example if tParam is allocated on the stack). – Hristo Iliev May 05 '12 at 21:02
  • @HristoIliev ah ok. Well, he didn't include a declaration. It's not something I'd do (destroy the outside scope before the threads are created) and I don't like the idea of passing an integer variable in a pointer type either - all kinds of size issues. Let's just say people assuming pointer types are 4-bytes has caused me lots of pain recently. An example where this'd hurt is passing `uint64_t` through a `void*` on a 32-bit system. So if it's really common practice, it ought not to be. –  May 05 '12 at 21:10
1

You can call pthread_self(). It returns a unique thread id. See the API reference at the LLNL URL that juampa recommended.

No One in Particular
  • 2,846
  • 4
  • 27
  • 32
-2

I do not understand your question; I still cannot figure out what you really would like to do.

In any case, I would strongly recommend you to check the sites:

They are short but still contain most of the stuff you shall likely need to get started.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
jpmuc
  • 1,092
  • 14
  • 30
  • Im working on a mutli-threaded webserver, using producer consumer algorithm with semaphores, i want to give each FD from the buffer to the specific worker thread so it can serve that connections. – CodeRed May 05 '12 at 20:10