Passing funcion to pthread_create

Hello, I am currently playing with the pthread_create.
I have a test function called void *abaco (void *threadid) that is used on pthread.

However my intention is to use pthread_create with a function that currently belongs to a class.
To test if is possible to replace abaco by a function belonging to a class, a created a "test" function, belonging to the same class where lies the function that I truly want to use with pthread_create ().
It's defined:
void * File_list::test (void * test) {
cout << "Testing..." << endl;
}


Basically, its declaration is the same as "abaco", except that obviously it is inside a class.

When I try to call it with

1
2
3
4
5
6
int rc,i;
   File_list ry;
   for (int i=0; i<2; i++) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create (&threads[i], NULL, ry.test, (void *)i);
   }


I end receiving
main.cpp|67|error: argument of type ‘void* (File_list::)(void*)’ does not match ‘void* (*)(void*)’|


So is there a way to call a function belong to a class in pthread_create or not?
For me it would not be a big problem moving it from the class File_list to main, since its the only thing that the class does have are the test function and the goal function, but I imagine that it would became worst, relative to the program organization if it belonged to a more complex class, or if there is a need to call pthread_create with several methods that belongs to many different class.

What would be a good approach on these occasions
You can use a static member function. If you pass the address of the object as argument you can let the static member function call a non-static member function on the object.

1
2
3
4
5
6
7
8
9
10
11
class File_list
{
public:
	void test() {
		cout << "Testing..." << endl;
	}
	static void* run_thread (void* ptr) {
		static_cast<File_list*>(ptr)->test();
		return nullptr;
	}
};

 
rc = pthread_create(&threads[i], NULL, File_list::run_thread, &ry);
Last edited on
Thanks for the reply. But if I pass the object's address as the last argument of pthread_create, how can I send information specific about the current's thread identification, so I can make the function inside the class to behavior differently according to the calling thread?

I could make something like
1
2
3
4
5
6
7
for (int i=0; i<2; i++) {
      cout << "main() : creating thread, " << i << endl;
      if (i==0)
          rc = pthread_create (&threads[i], NULL, File_list::run_thread, &ray);
      else ()
          rc = pthread_create (&threads[i], NULL, File_list::run_thread2, &ray);
} 


1
2
3
4
5
6
static void* run_thread (void * a) {
         void *nullptr; 
         static_cast <File_list*>(a)->test();
         cout << "test1..." << endl;
         return nullptr;
      }


1
2
3
4
5
6
static void* run_thread2 (void * a) {
         void *nullptr;
         static_cast <File_list*>(a)->test2();
         cout << "test2..." << endl;
         return nullptr;      
   }


But is ugly and will force a lot of code duplication, since the real function on File_list in the place of test is quite big.
I guess you could use a struct, that contains both a pointer to the object and the thread specific data, and pass that as last argument to pthread_create instead.
Last edited on
Ok, I am lost.

Do you mean something like this:

1
2
3
4
struct thread_data {
         int thread_index;
         File_list * file_list_ptr;
};


Instead of doing

File_list ry;

should I do thread_data td; ..

and then the call for pthread_create becames: rc = pthread_create (&threads[i], NULL, File_list::run_thread, &td);

but what modifications shall I do to
1
2
3
4
static void* run_thread (void* ptr) {
		static_cast<File_list*>(ptr)->test();
		return nullptr;
	}


The void pointer of static void* run_thread (void* ptr) is now receiving a pointer to a structure thread_data, no more a pointer to a File_list instance, so to leave the "run_thread" code unaltered could unleash unexpected results? If the static cast is made to thread_data it will not compile. If I want to pass the thread_id member to the test member function, how I could do it? I guess it cannot be static_cast<File_list*>(ptr)->test(ptr->thread_id);

So, how should I proceed?
Last edited on
You still need the File_list object. That's where file_list_ptr should point to.

1
2
thread_data* td = static_cast<thread_data*>(ptr);
td->file_list_ptr->test(td->thread_index);

Note that you need one thread_data object per thread.


Did you know that C++ has its own thread support now? If you can use it (requires C++11 or later) you might want to consider using it instead of pthread (which is a C API) because it makes it much easier to use member functions and you can easily pass any number of arguments. It's also more type safe (no casts are necessary).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <thread>

using namespace std;

class File_list
{
public:
	void test(int i) {
		cout << "Testing... " << i << endl;
	}
};

int main()
{
	const int N = 2;
	thread threads[N];
	
	File_list ry;
	
	// start threads
	for (int i = 0; i < N; i++) {
		cout << "main() : creating thread, " << i << endl;
		threads[i] = thread(&File_list::test, &ry, i);
	}
	
	// wait for threads to finish
	for (int i = 0; i < N; i++) {
		threads[i].join();
	}
}
Last edited on
I am getting some issues. If I define the thread_data on the main.cpp, before main () starts. I receive several complaints like these:

|17|error: ISO C++ forbids declaration of ‘File_list’ with no type|
|17|error: expected ‘;’ before ‘*’ token|


on the second line of the struc declaration
1
2
3
4
struct thread_data {
   int thread_index;
   File_list* File_list_ptr;
};


|55|error: ‘File_list’ has not been declared|
when doing the call to: rc = pthread_create (&threads[i], NULL, File_list::run_thread, &td);

|65|error: ‘File_list’ was not declared in this scope|
and
|65|error: ‘fl’ was not declared in this scope|
when doing: File_list fl

There is a #include "RayTracer.h" on main.cpp and #ifndef #define #endif directives on File_list.h


Now, if the thread_data is inside the File_list class, I receive:

|45|error: ‘thread_data’ was not declared in this scope|
on thread_data td;, plus all the same complaints that I received on lines 55 e 65. And there is A #include "File_list.h" on main.cpp

I knew about the native C++11 support of threads. The problem is that I would need to update or change my compiler which would be a burden at the moment, plus, since I already I am using pthreads, I want to make it work with my program before thinking on other possibilities



If you define thread_data before File_list you need to add a forward declaration of File_list so that the compiler knows it's a class when it sees the pointer type File_list*.

1
2
3
4
5
6
class File_list;

struct thread_data {
   int thread_index;
   File_list* File_list_ptr;
};
Thanks for reply, it worked.

My code currently is:

on main.cpp
1
2
3
4
5
6
thread_data td;
   for (int i=0; i<2; i++) {
      cout << "main() : creating thread, " << i << endl;
      td.thread_index=i;
      rc = pthread_create (&threads[i], NULL, File_list::run_thread, &td);
   }


on File_list.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int test (int thread_id) {
    cout << "test!, Thread id" << thread_id << endl;
    int a [10];
    if (thread_id==0) {
        for (int i=0; i<10; i++)
        a [i] =  5;//i*((((i+59)*247)+53)/55);
    }
    if (thread_id==1) {
        for (int i=0; i<10; i++)
        a [i] = 10;//i*((((i+59)*247)+53)/55);
    }
    for (int i=0; i<10; i++)
        cout << a[i] << ' ';
        pthread_exit (NULL);
    }


Unfortunately, it produces several different outputs. At least four. Only one is the intended one and that one I was not able to replicate during the several last runs of the program. Here is the three that I was able to reproduce:

main() : creating thread, 0
main() : creating thread, 1
run_thread...
test!, Thread id1
10 10 10 10 10 10 10 10 10 10 File_list::another_method
Another_class::method_from_another_class:
count: 0

test!, Thread id1
10 10 10 10 10 10 10 10 10 10


main() : creating thread, 0
main() : creating thread, 1
File_list::another_method
Another_class::method_from_another_class:
count: 0
run_thread...
test!, Thread id1
10 10 10 10 10 10 10 10 10 10 run_thread...
test!, Thread id1
10 10 10 10 10 10 10 10 10 10


main() : creating thread, 0
td.thread_index: 0
main() : creating thread, 1
td.thread_index: 1
run_thread...
test!, Thread id1
10 10 10 10 10 10 10 10 10 10 File_list::another_method
Another_class::method_from_another_class:
count: 0
run_thread...
test!, Thread id1
10 10 10 10 10 10 10 10 10 10


As can be seen the program is not executing the way I intend it to do, since there should be a
test!, Thread id0
5 5 5 5 5 5 5 5 5 5
. As I said, it did happen a couple of times, but in all recent attempts I end with one of the cases above,

I will try to use join to see if I can solve it, but I am not sure, since its purpose seems to be to make the threads to end execution in a correct order.

So I wonder if there is a visible bug or if I shall try to add join code to solve it.
Last edited on
You need to use one thread_data object per thread.
Right, but how can I accomplish it?

I threw thread td inside the loop

1
2
3
4
5
6
7
for (int i=0; i<2; i++) {
      thread_data td;
      cout << "main() : creating thread, " << i << endl;
      td.thread_index=i;
      cout << "td.thread_index: " << td.thread_index << endl;
      rc = pthread_create (&threads[i], NULL, RayTracer::run_thread, &td);
   }


but it did not change the behavior
You could create an array like you did for the pthread_t (you could even store them together in the same array if you want by storing the pthread_t in the thread_data struct).
It seems to be working now.

Another problem unfortunately came up. I modified the code of the test method to:

1
2
3
4
5
6
7
8
9
10
11
int test (int thread_id) {
         cout << "test!, Thread id" << thread_id << endl;
         if (thread_id==0) {
            for (int i=0; i<5; i++)
               b [i] =  5;//i*((((i+59)*247)+53)/55);
         }
         if (thread_id==1) {
            for (int i=5; i<10; i++)
               b [i] = 10;//i*((((i+59)*247)+53)/55);
         }
      }


whose different to the older version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int test (int thread_id) {
    cout << "test!, Thread id" << thread_id << endl;
    int a [10];
    if (thread_id==0) {
        for (int i=0; i<10; i++)
        a [i] =  5;//i*((((i+59)*247)+53)/55);
    }
    if (thread_id==1) {
        for (int i=0; i<10; i++)
        a [i] = 10;//i*((((i+59)*247)+53)/55);
    }
    for (int i=0; i<10; i++)
        cout << a[i] << ' ';
        pthread_exit (NULL);
    }


is that now I am using an array that belongs to the class
1
2
3
   private:
      float b [1000];
};
and I am trying to do that each thread writes half of it concurrently.

Unfortunately I am receiving:
main() : creating thread, 0
td_array.thread_index: 0
main() : creating thread, 1
td_array.thread_index: 1
run_thread...
td->thread_index: 0
test!, Thread id0
Segmentation fault


why is that happening? I am not close to the end of the array.
In previous posts it looks like you have forgotten to set the td.File_list_ptr pointer.
Thanks, I tried this:

1
2
3
4
5
6
7
8
9
10
11
   pthread_t threads [2];
   thread_data td_array [2];
   Filelist fl; // NEW CODE
   int rc;
   for (int i=0; i<2; i++) {
      cout << "main() : creating thread, " << i << endl;
      td_array[i].thread_index=i;
      td_array[i].rt_ptr = &fl; // NEW CODE
      cout << "td_array.thread_index: " << td_array[i].thread_index << endl;
      rc = pthread_create (&threads[i], NULL, RayTracer::run_thread, &td_array[i]);
   }


and then to check the values:
1
2
3
4
5
6
7
8
9
10
cout << "rt.d[0]: " << rt.d[0] << endl;
   cout << "fl.d[1]: " << fl.d[1] << endl;
   cout << "fl.d[2]: " << fl.d[2] << endl;
   cout << "fl.d[3]: " << fl.d[3] << endl;
   cout << "fl.d[4]: " << fl.d[4] << endl;
   cout << "fl.d[5]: " << fl.d[5] << endl;
   cout << "fl.d[6]: " << fl.d[6] << endl;
   cout << "fl.d[7]: " << fl.d[7] << endl;
   cout << "fl.d[8]: " << fl.d[8] << endl;
   cout << "fl.d[9]: " << fl.d[9] << endl; 


This SEEMS to be working, but the results being printed will vary wildly.

Here some different outputs:

main() : creating thread, 0
td_array.thread_index: 0
main() : creating thread, 1
td_array.thread_index: run_thread...1
td->thread_index: 0
test!, Thread id0

fl.d[0]: 5 5 5 5
run_thread...
td->thread_index: 1
test!, Thread id1fl.d[1]: 5 5
fl.d[2]: 55
fl.d[3]: 5
fl.d[4]: 0 5
fl.d[5]: 0

fl.d[6]: 4.85997e-08 10
10 fl.d[7]: 10 1010
fl.d[8]: 10
fl.d[9]: 10
5 5 5 5 5 10 10 10 10 10


main() : creating thread, 0
td_array.thread_index: 0
main() : creating thread, 1
td_array.thread_index: 1
run_thread...
td->thread_index: 0
test!, Thread id0
fl.d[0]: 55
run_thread...
td->thread_index: 1
test!, Thread id1
5 5 5 5 5 5 5 5 5 10 10 10 10 1010 10 10 10 10 fl.d[1]: 5
fl.d[2]: 5
fl.d[3]: 5
fl.d[4]: 5
fl.d[5]: 10
fl.d[6]: 10
fl.d[7]: 10
fl.d[8]: 10
fl.d[9]: 10


The first time it seems to be executing the printing code before actually attributing the values to the array, leading to these strange cases where it appears that several values are being printed from a single array position, like:
fl.d[7]: 10 1010
. The second time it worked closed to expected, with the notable exception of
fl.d[0]: 55
.

So, shall I give a look in join now to try to keep things synchronized, or there still is something wrong with my code?
If you want to avoid interleaved output you need to synchronize the use of cout so that the threads doesn't use it at the same time.

Not sure what the rt.d array is but it looks like you might have a data race. If you are printing it in the main thread but write to it from the two other threads you might want to use pthread_join to wait until the threads have finished before printing it.
Last edited on
Topic archived. No new replies allowed.