0

I am practicing concurrent programming. My ultimate goal is applying the multiple thread on OpenCV and 3rd party software. I am reading the following URL.
http://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm

      rc = pthread_create(&threads[i], NULL, 
                          PrintHello, (void *)i);

It returns me an error.

$ g++ simpleThread.cpp -lpthread
simpleThread.cpp: In function ‘int main()’:
simpleThread.cpp:25:47: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
                           PrintHello, (void *)i);

Then I read http://stackoverflow.com/questions/21323628/warning-cast-to-from-pointer-from-to-integer-of-different-size Add long

  rc = pthread_create(&threads[i], NULL, 
                      PrintHello, (void *)(long)i);

Program works.

Question :
I don't understand at all. Why I have to put long in here?
Where, what topic, book, URLs I can start?

Update :
Thank you everyone for your attention. Casting by long returns me acceptable result.

rc = pthread_create(&threads[i], NULL, 
                          PrintHello, (void*)(long)i);

Run the program.

$./simpleThreadLong.out 
main() : creating thread, 0
main() : creating thread, 1
Hello World! Thread ID, 0
main() : creating thread, Hello World! Thread ID, 2
1
main() : creating thread, 3
Hello World! Thread ID, 2
main() : creating thread, 4
Hello World! Thread ID, 3
Hello World! Thread ID, 4

Whereas ampersand returns unknown ID.

  rc = pthread_create(&threads[i], NULL, 
                      PrintHello, &i);

Run the program.

./simpleThreadAmpersand.out 
main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
Hello World! Thread ID, 140722119501784
Hello World! Thread ID, 140722119501784
Hello World! Thread ID, 140722119501784
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 140722119501784
Hello World! Thread ID, 140722119501784

Update2:

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS     5

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   cout << "Hello World! Thread ID, " << tid << endl;
   pthread_exit(NULL);
}

int main ()
{
   pthread_t threads[NUM_THREADS];
   int rc;
   int i;
   for( i=0; i < NUM_THREADS; i++ ){
      cout << "main() : creating thread, " << i << endl;
      //rc = pthread_create(&threads[i], NULL, 
      //                    PrintHello, (void *)(long)i);
      rc = pthread_create(&threads[i], NULL, 
                          PrintHello, &i);
      if (rc){
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}
joe
  • 8,383
  • 13
  • 61
  • 109
  • 2
    Notice that the warning message mentions "different size"? My guess is that you're on a 64-bit platform where `int` is 32 bits and `long` *and* pointers are 64 bits. – Some programmer dude Dec 17 '15 at 15:45
  • @JoachimPileborg. Yes. I am coding on 64bit GNU/Linux Debian Jessie. So do you mean I have to use `long i` instead of `int i`? – joe Dec 17 '15 at 15:47
  • 2
    You should probably be learning `std::thread` instead of `pthread`, though I don't know if you have a particular use case where you cannot use `std::thread` – SirGuy Dec 17 '15 at 15:49
  • 1
    The warning probably tells you about a serious bug in your code. The cast to suppress the warning doesn't fix the bug. It just implies to the compiler that you did that questionable operation on purpose and don't want to be warned. – JSF Dec 17 '15 at 15:50
  • @GuyGreer. Any `thread` library are fine. Do you have any recommend one for particular job in OpenCV? I want to do feature extraction from multiple webcam all at once just that. – joe Dec 17 '15 at 15:52
  • Possible duplicate of [Cast int to pointer - why cast to long first? (as in p = (void\*) 42; )](http://stackoverflow.com/questions/25381610/cast-int-to-pointer-why-cast-to-long-first-as-in-p-void-42) – hlscalon Dec 17 '15 at 16:03
  • 1
    @Sarit C++11 has much better threading capabilities than the POSIX C-API. I recommend you read up on `std::thread`, `std::async` etc. https://isocpp.org/files/papers/5-Tour-Util.pdf is a good starting point. – Jens Dec 17 '15 at 16:18
  • @Jens. Thank your I will start from them. – joe Dec 17 '15 at 16:21

2 Answers2

3

I assume because on your platform, a pointer is the same size as long.

In general, you don't want to be casting integer types to pointers. And I'm thinking that functions takes an address of it's argument so your code won't work. You probably need to pass & i.

EDIT After reading your link it looks like the example is using a bit of a hack in the first example and is doing exactly what I don't recommend above. But then second example he/she is doing it correctly.

EDIT 2 After seeing the MCVE you need to change this:

   long tid;
   tid = (long)threadid;

to this:

   int tid;
   tid = *((int *)threadid);

But that will produce spurious results because the variable i in main (whose address you are passing into each thread) is changing. Plus it is not protected by some synchronization mechanism.

Bottom line is you can use the hack they use in the first example of your post to make it work. But the carefully read how the do the second example.

Anon Mail
  • 4,660
  • 1
  • 18
  • 21
  • Sometimes people use `void*` as a way to pass arbitrary data, as is the case with `pthread_create`. – SirGuy Dec 17 '15 at 15:47
  • And what if the `i` variable is the counting variable in a `for` loop? Passing a pointer to that will make all threads have the same pointer and the same value. Also what's worse is that the variable can have gone out of scope while the threads are running leaving the threads with a stray pointer leading to undefined behavior. No there are certain cases where casting a normal integer variable to pointer might be an acceptable solution, not many but there are certain cases, and this IMO is one of those cases. – Some programmer dude Dec 17 '15 at 15:48
  • @Anon Mail. `&i` can run the thread, but `thread ID` is strange. – joe Dec 17 '15 at 16:08
  • @Sarit that's because you will have to cast it back to a pointer to an integer and then dereference it to access the integer. Assuming the integer is still in scope in the calling function. – Anon Mail Dec 17 '15 at 16:09
  • @Anon Mail. I am trying to understand your answer. – joe Dec 17 '15 at 16:20
  • If you add a complete example [MCVE](http://stackoverflow.com/help/mcve) I can tell you exactly where the problem is. – Anon Mail Dec 17 '15 at 16:30
  • If added an EDIT 2 to my answer. – Anon Mail Dec 17 '15 at 16:41
  • @AnonMail. That's ok now. Your EDIT2 create `thread [0,4] but Hello World Thread ID is [1,5]. It shift by 1. Let me start a new question when I finish reading first. Thank you for you attention. :) – joe Dec 17 '15 at 17:00
1

On most 64-bit platforms, standard sizes for int and pointers are different. int is often still 32-bit, but pointers are 64-bit since they must be able to represent 64-bit addresses. You can easily check it on your platform by printing

std::cout << sizeof(int) << std::endl << sizeof(void*) << std::endl;

On my Linux system, this prints 4 and 8. The compiler just complains that you are casting a signed 32-bit value to an unsigned 64-bit value.

The POSIX thread API gives you the possibility to pass arbitrary data to the created thread. Arbitrary data in C means something of unknown size and type, and the only thing you know is an address to an object. This is a void*. Another way to fix your problem is to dynamically allocate the data and pass the address to the thread:

rc = pthread_create(&threads[i], NULL, 
                          PrintHello, new int(i) );

PrintHello than has to cast the void* to an int* to use the data.

void PrintHello(void* data) {
    std::unique_ptr<int> i( static_cast<int*>(data) );
}

With C++11, you can skip all that and just use a better abstraction:

void PrintHello(int i);

int i = 42;
auto t1 = std::thread( PrintHello, i ) { /* do something with i */ };
// or preferably use std::async
auto f = std::async(std::launch::async, PrintHello, i);
Jens
  • 9,058
  • 2
  • 26
  • 43
  • Thank you for your reply. Now I have a huge material waiting for me in parallel world of C++11. – joe Dec 17 '15 at 16:43
  • 1
    @Sarit You're welcome. There is also the book C++ Concurrency in Action (https://www.manning.com/books/c-plus-plus-concurrency-in-action) which is often recommended. You should also consider to not touch the low-level threading at all (Not doing manual mutexes etc. is a good design decision) and use a higher-level abstraction library. Intel TBB or Microsoft PPL are two prominent examples. – Jens Dec 17 '15 at 17:18