简体   繁体   中英

Why does a function accept a void pointer?

I am trying to understand pthread.

However It is required to create thread methods as follows:

void *SomeMethod(void* x)
{
    //Do Something
}

Why is it necessary to create a function that accepts a void pointer? Can't we use pthread with a function like this?

void SomeMethod()
{
}

Because the pthread_create function takes an argument of type void* (*)(void*) which is a function taking a void* and returning a void* , so to create a thread using pthread_create that's what you need to use.

The pthread_create API takes that to allow you to pass data to the new thread and get data back again. If you don't want to pass anything in you still have to meet that interface, but just pass it NULL.

Just because you don't want to pass any arguments to your new thread right now doesn't mean the API should be designed to only support your current use case. It's much better to have an API written in terms of a function taking void* (which can optionally be passed NULL) than to have an API in terms of a function taking no arguments and requiring users to come up with their own solutions for passing data to the new thread.

In C++ you can use any type of function for the new thread and pass it whatever arguments you need to:

std::thread t(&SomeMethod);

Because they wanted to write just the one function for creating threads - to take and return data.

Otherwise they would have to write at least four possibilities.

You are free you ignore the input parameter and the return value.

Just a matter of simplicity

As per the man page of pthread_create() , we can see, the signature of the function is

 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
               void *(*start_routine) (void *), void *arg);

where the third argument is of type

void *(*start_routine) (void *)

which means, it expects a pointer to a function with return type void * and accepting a void * argument. So, we need to define the thread function accordingly.

That said, regarding the usage of void pointer for argument passing, quoting C11 , chapter §6.3.2.3

A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

As we can see, the void pointer is used to pass any type of data to the thread function , provided, it is converted back to the actual type inside the function.

Also, FWIW, do not try to deviate from the required signature of a function pointer, as the standard clearly mandates

[....] If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined. In case you don't want (need) to pass any valid argument value, you can always pass NULL .

Because quite often, we want to give the thread something to work on (or with, or off, or whatever). A very typical example is to pass in an instance of a class, so you can make calls to the class member functions.

But it could be all sorts of other things - a struct, or a pointer to some simple data.

Of course, using std::thread will hide most such things anyway, and you don't need to worry about it. I would strongly suggest using std::thread instead of pthread in general.

void *SomeMethod(void* x) is used as an entry point for the new thread. How should you act if you want to pass to the new thread some data (struct, buffer, a regular integer, etc.)? Specially for this entry point method receives void* argument which can point to anything you want. Then inside the function body you can cast it back to the proper type and use it by the worker thread.

In case your thread doesn't need any additional data you can pass NULL or nullptr (for C++11) to it.

No, the method signature you propose will not work as the start function for a pthreads thread. If you pass a pointer to such a function to pthread_create() then the compiler should warn. If you run the resulting program then you invoke undefined behavior, because the pointer does not have the correct type. As a practical matter, the pthreads library will try to pass an argument to to the start function, and will expect a return value from it; if you provide a pointer to a function that does not both consume an argument and return a value (both of appropriate type) then very likely the program will crash.

As for why the start function is required to have the signature it does, a void * argument can be used to convey an actual argument of any type, including a composite type encompassing multiple distinct values, and similarly, a void * return type can be used to convey a return value of any type. This is pretty much the most general function type possible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM