Correct Way of Passing Pointer to Another Thread

Correct way of passing pointer to another thread

How do you run func1() and func2() under different threads? func1() directly calls func2(), so they run under the same thread. Even the first implementation of func1() should work, as the array is still in its place.

EDIT:

But calling func2() directly from within func1() isn't an "asynchronous call to func2()" (even if at some other point it's used as a thread function). "Asynchronous call" means creating a new thread with func2() as the thread function. If so, this behaviour is very much expected, because func1() may have exited when func2() runs, and the array wouldn't exist by that time. On the other hand, the heap-block would still be allocated, so this would work. func2() should release the block then.

EDIT2:

Ummm, yes, the 2nd version is indeed an "asynchronous call to func2()", so the objects' lifetime considerations listed above indeed apply.

Pass pointer to on-stack variable for new thread - is this code safe?

Is that a real concern?

Yes. Its not a safe way of doing it.

You can pass the value directly instead of passing its address.

pthread_create(&client_thread, NULL, echo_data, (void*) incoming_client_socket);`

and the thread function should be like

void* echo_data(void* client_socket) {
int socket = (int)client_socket;
/* your code */
}

If you wish to pass more than one elements to the thread, then you could wrap it inside a structure, create a structure pointer for it, allocate memory and fill the values and pass the pointer to the threads.

struct X {
int socket;
/* other members here*/
};

and

  while (1) {
int incoming_client_socket = wait_for_connection(server_socket);
fprintf(stdout, "new connection accepted...\n");
struct X *ptr = malloc (sizeof(struct X));
ptr->socket = incoming_client_socket;
/* other assignment here */

pthread_create(&client_thread, NULL, echo_data, (void*)ptr);
}

And your thread func should look like

void* echo_data(void* client_socket) {
// for the sake of argument - suppose there's a lot of code here before we copy the socket to local variable:
struct X *ptr = (struct X *)client_socket;
// send back whatever is coming from client
return (void*)0;
}

Don't forget to free the memory.

Passing pointer to a member function to a seperate thread

PostMessage is not a great way to marshall function pointers and work work items between threads. You're better off just inventing your own thread-safe data structure and queuing work items to the the render thread.

But if you are really bent on passing a function using PostMessage... then std::function combo'd with a lambda could work.

Declare this in a common header file:

struct MyCustomMessage
{
std::function<void()> fn;
};

From the ViewPortController thread, do this to "send" the function invocation to the other thread.

MyCustomMessage *pMsg = new MyCustomMessage();
pMsg->fn = [this](){
this->DrawSomeStuff();
};
PostThreadMessage(uiThreadID, UWM_DRAW, 0, reinterpret_cast<LPARAM>(pMsg);

In the other thread:

ThreadController::draw(WPARAM wParam, LPARAM lParam) {

MyCustomMessage* pMsg = reinterpret_cast<MyCustomMessage*>(lParam);

pMsg->fn();

delete pMsg;
}

Passing pointer as argument with std::thread function C++11

The immediate problem which triggers compilation error is right here:

void checkMin(int value);

This is the prototype of your function, and it is incorrect - it should be

void checkMin(int* value); //<-- not the pointer.

But this is not the only one! Your code makes no sense. Look at this fragment:

std::thread tabThreads[threadCount];
std::thread *ptrTabThreads = tabThreads;

for (int i = 0; i < threadCount; ++i) {
ptrTabThreads = new std::thread(checkMin, ptrTab[i]);
ptrTabThreads->join();
++ptrTabThreads;
}

What's the purpose of all this jumping with pointers? You also have a leak in your code, since you are modifying the pointer you obtained from new before deleteing it. Why not use following simple code?

std::array<std::thread, threadCount> tabThreads;

for (int i = 0; i < threadCount; ++i) {
tabThreads[i] = std::thread(checkMin, ptrTab[i]);
tabThreads[i].join();
}

This still serves no pratical purpose (application remains effectively single-threaded, since you join your thread right after creating it), but at least, the code is correct. To really do some fancy multithreading, you need your loop to look like following:

for (int i = 0; i < threadCount; ++i)
tabThreads[i] = std::thread(checkMin, ptrTab[i]);

for (std::thread& t : tabThreads) // so-called range-for loop. Nice thing!
t.join();

This will paralellize stuff!

Instantiating a pointer and passing it to two Queues to be consumed by two Threads?

Does that mean that the object only gets deleted when it gets pulled out of both of the threads reading from this queue and then only the data_ptr memory allocated gets deleted?

No it doesn't. The first use of std::move will 'rob' data_ptr and the second is, effectively, UB.

Don't be afraid to copy a std::shared_ptr. It is a cheap operation and doesn't copy the underlying data. In fact, that is the whole idea behind std::shared_ptr - to share ownership of whatever it points to, with the object being deleted when the last shared_ptr goes out of scope.


If you're desparately worried about performace (which I am not) then you could pass data_ptr to data_queue_.write by value (thus making a copy) and to custom_queue_.write by reference (thus not making a copy). In neither case is std::move appropriate or useful.

But code like this is fragile. I strongly recommend you keep things simple and pass data_ptr by value in both cases. This is how shared_ptr is meant to be used. People don't talk about modern C++ having value semantics for nothing.

When is passing a pointer to another thread in C++11 a race condition?

No in both cases.

The first example would in principle be a definite race condition if it wasn't for some special properties of std::thread.
The compiler is in principle allowed to reorder moves, however constructing a thread object has sequential consistency, which formally guarantees that it works. But even if it didn't have that property, creating and starting a thread in practice takes a very considerable time (hundred thousands to millions of times as long as executing a few move instructions) so you would practically (not formally, but practically) be guaranteed that there is no race, even if there was no sequential consistency (this "practical guarantee" is admittedly somewhat disputable, it might not hold true in contrieved extreme cases, but the formal guarantee is true either way).

The second example uses a concurrent queue, which by definition is engineered (either using a lock or using a lockfree algorithm) in such a manner that no race condition occurs.1

In either case, the pointer that ends up being in the queue is guaranteed to be either not there at all (in which case the pop operation will block or fail, where "fail" means that the consuming thread knows that there is no valid pointer available at this time -- it will not assume some invalid value) or it is there in a valid state.
The atomic (locked or lock-free) operation that adds the pointer to the queue guarantees that the object construction which happened before is also realized before (i.e. no pointer on queue without valid object).

This implies that the object must also be valid when its pointer is retrieved from the queue (unless you cheat).



1This obviously assumes correct operation of the queue, but that's a fair assumption.

Passing Custom Class Pointer to Another Thread via signal/slot mechanism in Qt

I've found the solution, thanks To @G.M

We need to register the type exactly how we are going to use it, such as:

qRegisterMetaType<std::shared_ptr<ITradeMessage>>()


Related Topics



Leave a reply



Submit