[SOLVED] Which Thread library for secure argument passing ?

Hi all,

I am a thread newbie. I read several tutorials and I experiment. pthread seems to not be secured with argument passing. Here is my test code :

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
32
33
34
35
36
37
38
39
40
41
#include <cstdlib>
#include <pthread.h>

void* my_thread(void* data);

int main(int argc, const char *argv[]) {
	switch (atoi(argv[1])) {
		case 11 : { // test of pthread
			pthread_t thread[8];
			// create 8 threads
			for (int i = 0; i < 8; i++) {
				printf("Create thread n° %i\n", i); //cout is to much interrupted, making the output hardly readable.
				pthread_create(&(thread[i]), NULL, my_thread, (void*)&i);
			}
			//Wait termination of the threads
			void **thread_return;
			for (int i = 0; i < 8; i++) {
				if (pthread_join(thread[i], thread_return) == 0) {
					printf("Thread %i finished rigth\n", i);
				}
				else {
					printf("Issue at the join step for thread n° %i", i);
				}
				if (thread_return == 0) {
					printf("The function called in the thread n° %i finished right", i);
				}
				else {
					printf("The function called in the thread n° %i has return the error code %i", i, *thread_return);
				}

			}
		}
	}

	return 0;
}

void* my_thread(void* data) {
	int* p_i = static_cast<int*>(data);
	printf("Execution of my_thread. Argument passed = %i", *p_i);
}


Here is the output :

Create thread n° 0
Create thread n° 1
Execution of my_thread. Argument passed = 1
Create thread n° 2
Execution of my_thread. Argument passed = 2
Create thread n° 3
Execution of my_thread. Argument passed = 3
Create thread n° 4
Execution of my_thread. Argument passed = 4
Create thread n° 5
Execution of my_thread. Argument passed = 5
Create thread n° 6
Execution of my_thread. Argument passed = 6
Create thread n° 7
Execution of my_thread. Argument passed = 7
Execution of my_thread. Argument passed = 8
Thread 0 finished right
The function called in the thread n° 0 finished right
Thread 1 finished right
The function called in the thread n° 1 finished right
Thread 2 finished right
The function called in the thread n° 2 finished right
Thread 3 finished right
The function called in the thread n° 3 finished right
Thread 4 finished right
The function called in the thread n° 4 finished right
Thread 5 finished right
The function called in the thread n° 5 finished right
Thread 6 finished right
The function called in the thread n° 6 finished right
Thread 7 finished right
The function called in the thread n° 7 finished right


I expected that the argument passed in thread n°i was i and not i+1. So it seems that main computes i++ in the for loop between the creation of the thread and the initialization of the arguments of my_thread.

So :

1) Do I misuse pthread ?
2) There exist several thread libraries like Boost or ThreadJack. Are some secured for argument passing ? Which one do you advise ?
Last edited on
Argument passing is perfectly safe, as long as the parameters you're passing aren't currently being modified by other threads. Which is impossible here, because neither the address of my_thread nor i is mutable.

However, to all threads, you're passing a pointer to the same (!), local (!!) variable i, which is wrong. By the time any of the threads begin execution, i might be long destroyed.

1) Do I misuse pthread ?

Yes. If you want the calls to be performed sequentially, you should call my_thread regularly and not use threads.

2) There exist several thread libraries like Boost or ThreadJack.

Boost.Thread is a good library for the use in C++. But that has nothing to do with argument passing (well, actually it does - it makes it easier, among other things).
Last edited on
Thanks for your answer Athar.

Argument passing is perfectly safe, as long as the parameters you're passing aren't currently being modified by other threads.
great ! So I have to put the arguments in a global table of structure where each element of the table contains all the arguments for one uniq thread.

By the time any of the threads begin execution, i might be long destroyed.
If my understanding is correct, the problem I have depicted was predictable in my code - i is changed between the thread creation in main and the thread execution. But i is not destroyed before all the threads are terminated since I wait for all of them in main with join.

If you want the calls to be performed sequentially, you should call my_thread regularly and not use threads.
No, I read about processes, fork and threads and I do need threads to parallelize heavy tasks among my 8 cpu cores.

Same using C++ threads. On linux, they are available with both GCC and Clang compilers.

Unlike pthreads, C++ threads (and boost.threads from which they evolved) pass arguments to threads by value (by default)

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
#include <cstdio>
#include <vector>
#include <string>
#include <thread>

void my_thread(int data) {
    printf("Execution of my_thread. Argument passed = %i\n", data);
}

int main(int argc, const char *argv[]) {
     switch (std::stoi(argv[1])) {
        case 11 : {
            std::vector<std::thread> thread;
            // create 8 threads
            for (int i = 0; i < 8; i++) {
                printf("Create thread n° %i\n", i);
                thread.emplace_back(my_thread, i);
            }
            //Wait termination of the threads
            for (int i = 0; i < 8; i++) {
                thread[i].join();
                printf("Thread %i finished right\n", i);
            }
        }
    }
}
Create thread n° 0
Create thread n° 1
Create thread n° 2
Create thread n° 3
Execution of my_thread. Argument passed = 1
Create thread n° 4
Execution of my_thread. Argument passed = 0
Execution of my_thread. Argument passed = 4
Execution of my_thread. Argument passed = 2
Execution of my_thread. Argument passed = 3
Create thread n° 5
Create thread n° 6
Execution of my_thread. Argument passed = 5
Create thread n° 7
Execution of my_thread. Argument passed = 6
Execution of my_thread. Argument passed = 7
Thread 0 finished right
Thread 1 finished right
Thread 2 finished right
Thread 3 finished right
Thread 4 finished right
Thread 5 finished right
Thread 6 finished right
Thread 7 finished right


note that there's nothing wrong with using cout << either, it is guaranteed to be thread-safe, but you have to send your entire string at once, with just one operator<<. Or use a lock_guard

Last edited on
But i is not destroyed before all the threads are terminated since I wait for all of them in main with join.

It is. i is destroyed when your thread creation loop ends and no longer exists when the threads are being joined.
Athar
It is. i is destroyed when your thread creation loop ends and no longer exists when the threads are being joined.
Oups! Yes.

Cubbi
Same using C++ threads. On linux, they are available with both GCC and Clang compilers.
Great ! Thank you very much. It is very clean. But what version of gcc at least is required and with which options ? From http://gcc.gnu.org/projects/cxx0x.html , it is not obvious. I have gcc V. 4.4.5 and options -std=c++0x -std=gnu++0x, but it fails to compile :
request for member ‘emplace_back’ in ‘thread’, which is of non-class type ‘std::thread [8]’


C++ threads pass arguments to threads by value (by default)
: looks more conveniant.
lalebarde wrote:
request for member ‘emplace_back’ in ‘thread’, which is of non-class type ‘std::thread [8]’

Sounds like you attempted to use an array instead of a vector.

what version of gcc at least is required and with which options ?

for GCC 4.4-4.6, the options are -std=c++0x -pthread
for GCC 4.7, the options are -std=c++11 -pthread
Last edited on
Sounds like you attempted to use an array instead of a vector.
You are right. Sorry !

One thing looks strange to me. If I do it like you : vector<thread> thread;, it works. But if I declare it along with the size of the vector vector<thread> thread(8);, what should be correct, it fails to compile :

g++ -I"/home/alain/Documents/Poker/WorkSpace/MyUtils" -O0 -g3 -Wall -c -fmessage-length=0 -std=c++0x -std=gnu++0x -MMD -MP -MF"src/test.d" -MT"src/test.d" -o"src/test.o" "../src/test.cpp"
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/vector:63,
                 from /home/lalebarde/Documents/Project/WorkSpace/MyUtils/myUtils.h:15,
                 from ../src/test.cpp:15:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/thread: In function ‘void std::_Construct(_T1*, const _T2&) [with _T1 = std::thread, _T2 = std::thread]’:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_uninitialized.h:187:   instantiated from ‘static void std::__uninitialized_fill_n<<anonymous> >::uninitialized_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = std::thread*, _Size = long unsigned int, _Tp = std::thread, bool <anonymous> = false]’

BTW, do you have  a (some) good tutorial/reference link(s) for c++ thread
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_uninitialized.h:223:   instantiated from ‘void std::uninitialized_fill_n(_ForwardIterator, _Size, const _Tp&) [with _ForwardIterator = std::thread*, _Size = long unsigned int, _Tp = std::thread]’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_uninitialized.h:318:   instantiated from ‘void std::__uninitialized_fill_n_a(_ForwardIterator, _Size, const _Tp&, std::allocator<_Tp2>&) [with _ForwardIterator = std::thread*, _Size = long unsigned int, _Tp = std::thread, _Tp2 = std::thread]’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_vector.h:1035:   instantiated from ‘void std::vector<_Tp, _Alloc>::_M_fill_initialize(size_t, const _Tp&) [with _Tp = std::thread, _Alloc = std::allocator<std::thread>]’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_vector.h:230:   instantiated from ‘std::vector<_Tp, _Alloc>::vector(size_t, const _Tp&, const _Alloc&) [with _Tp = std::thread, _Alloc = std::allocator<std::thread>]’
../src/test.cpp:235:   instantiated from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/thread:122: erreur: deleted function ‘std::thread::thread(const std::thread&)’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4/bits/stl_construct.h:74: erreur: used here
make: *** [src/test.o] Erreur 1


BTW, do you have a (some) good link(s) for c++ threads tutorials/reference ?
erreur: deleted function ‘std::thread::thread(const std::thread&)’
It is trying to use the copy constructor, which thread does not have.
thread(const thread&) = delete;

Edit: wait, you are right. It shouldn't be copying them. It is working fine compiling in version 4.6.2
Last edited on
before C++11, vector<T>'s constructor that takes a single size_t argument was default-constructing a T() and then copy-constructing each element of the new vector from that value.

since C++11, vector<T>'s constructor that takes a single size_t argument default-constructs each T element individually, in-place. That was one of the changes that enabled vectors of non-copyable types.
Last edited on
Thank you very much for the clarification and help.
Topic archived. No new replies allowed.