9

How to pass int parameter to CreateThread callback function? I try it:

DWORD WINAPI mHandler(LPVOID sId) {
...
arr[(int)sId]
...
}

int id=1;
CreateThread(NULL, NULL, mHandler, (LPVOID)id, NULL, NULL);

But I get warnings:

warning C4311: 'type cast' : pointer truncation from 'LPVOID' to 'int'
warning C4312: 'type cast' : conversion from 'int' to 'LPVOID' of greater size
BArtWell
  • 4,176
  • 10
  • 63
  • 106

3 Answers3

7

Pass the address of the integer instead of its value:

// parameter on the heap to avoid possible threading bugs
int* id = new int(1);
CreateThread(NULL, NULL, mHandler, id, NULL, NULL);


DWORD WINAPI mHandler(LPVOID sId) {
    // make a copy of the parameter for convenience
    int id = *static_cast<int*>(sId);
    delete sId;

    // now do something with id
}
Jon
  • 428,835
  • 81
  • 738
  • 806
  • 1
    There is a problem with this if the thread outlives the scope of `id` – Zdeslav Vojkovic Sep 26 '12 at 08:07
  • @ZdeslavVojkovic: No, there is not. A copy is made by value first thing in the function. – Jon Sep 26 '12 at 08:08
  • 2
    It is still not safe. What if the new thread is not scheduled until the ID goes out of scope (which might be just after `CreateThread` call? – Zdeslav Vojkovic Sep 26 '12 at 08:13
  • Sorry, but it doesn't properly working. I look in debugger and see that: I pass into CreateThread 0 -> and receive 0, then 1 -> -858993460 and program crash... – BArtWell Sep 26 '12 at 08:17
  • @BArtWell: You are passing in `0` and `1` as the value of `id` right? I hope you are not passing them in as pointers... – Jon Sep 26 '12 at 08:18
  • @ZdeslavVojkovic: That one is a genuine concern. The pointer needs to point to the heap really. – Jon Sep 26 '12 at 08:19
  • I generally pass a struct containing all parameters, plus a condition variable signalling the creating thread that the parameters have been consumed and the thread started successfully. – Simon Richter Sep 26 '12 at 08:20
  • @ZdeslavVojkovic: Fixed. I 'm not happy with the newly introduced responsibility to dispose of the parameter (it's crude really) but let's keep it short. – Jon Sep 26 '12 at 08:23
  • @Simon Richter: but I need only one int, I think struct is surplus here. Or no? – BArtWell Sep 26 '12 at 08:23
  • @BArtWell: Does it still crash? – Jon Sep 26 '12 at 08:24
  • 1
    OK, with `new` and `delete` it is safe, but now it is enough to send `id` and not `&id` - that should be fixed in the code sample as the thread function assumes that it receives `int*` and not `int**`. This is also the reason why BArtWell sees those values/crash in the debugger – Zdeslav Vojkovic Sep 26 '12 at 08:25
  • @BartWell, programs tend to be extended later on, so use an easily extensible pattern from the beginning. – Simon Richter Sep 26 '12 at 09:35
2

You can make this warning go away by using appropriate types. In this case use INT_PTR or DWORD_PTR (or any other _PTR type) type instead of int (see Windows Data Types in MSDN).

DWORD WINAPI mHandler(LPVOID p)
{
    INT_PTR id=reinterpret_cast<INT_PTR>(p);
}
...

INT_PTR id = 123;
CreateThread(NULL, NULL, mHandler, reinterpret_cast<LPVOID>(id), NULL, NULL);
sdkljhdf hda
  • 1,387
  • 9
  • 17
0

I would use CreateThread(..., reinterpret_cast<LPVOID>(static_cast<INT_PTR>(id)), ...); and inside your thread function int my_int = static_cast<int>(reinterpret_cast<INT_PTR>(sId));

This also works with enums instead of int. It should work in both 32- and 64-bit mode.

Dirksche
  • 21
  • 3
  • 1
    Casting the argument type may silence warnings and errors but it *doesn't* fix the code. If the procedure expects the address of a `DWORD` as an argument, then you should give it the address of a `DWORD`, not just cast an 'arbitrary' value into what looks like an address. – Adrian Mole May 05 '21 at 13:24
  • The official documentation states that instead of a pointer you can pass in a scalar value. Some people use a single old fashioned C cast, but I don't like that. For some reason, you can static cast an INT_PTR to int, but you cannot static cast LPVOID to int. Therefore, in a first step, I'm reinterpret casting LPVOID to INT_PTR. Both are pointers and therefore will have the same size (32-bit when compiling in x86 mode and 64-bit when compiling in 64-bit). Thereafter, I static cast to int (which is 32-bit). There is no problem with this, unless someone didn't pass in an int, but a 64-bit value. – Dirksche May 06 '21 at 14:50