简体   繁体   English

键入将void *(*)(void *)转换为void(*)(void)

[英]Type cast void*(*)(void*) to void(*)(void)

As a part of an assignment, I am trying to create a user level thread library like pthreads. 作为分配的一部分,我试图创建一个用户级线程库,例如pthreads。

For handling the context switching between the threads, I am using 'swapcontext' function. 为了处理线程之间的上下文切换,我使用了'swapcontext'函数。 Before using it I have to make a context using 'makecontext' function. 在使用它之前,我必须使用“ makecontext”功能创建一个上下文。 'makecontext' expects a function pointer with return type void and argument type (void) . 'makecontext'需要一个返回类型为void且参数类型为(void)的函数指针。

Whereas, the thread function has to be of the type void* thread_func (void*) 而线程函数的类型必须为void* thread_func (void*)

Is there a way to do a typecasting? 有没有办法做类型转换? Or is there some other way to do context switching at the user level? 还是有其他方法可以在用户级别进行上下文切换?

It is illegal to invoke a function with an incompatible prototype by casting the address of the function to a different prototype and invoking it through the resulting pointer: 通过将函数的地址强制转换为其他原型并通过结果指针调用来调用具有不兼容原型的函数是非法的:

void *my_callback(void *arg) { ... }

void (*broken)(void *) = (void (*)(void *)) my_callback;
broken(some_arg);   // incorrect, my_callback returns a `void *`

What you can do is pass to makecontext your own callback which will call thread_func and ignore its return value. 您可以做的是将makecontext传递给您自己的回调,该回调将调用thread_func并忽略其返回值。 A small function that only serves to call another function is sometimes called a trampoline . 仅用于调用另一个功能的小功能有时称为蹦床

/* return type is compatible with the prototype of the callback received
   by makecontext; simply calls the real callback */
static void trampoline(int cb, int arg)
{
  void *(*real_cb)(void *) = (void *(*)(void *)) cb;
  void *real_arg = arg;
  real_cb(real_arg);
}

int my_pthread_create(void *(*cb)(void *), void *arg)
{
  ucontext_t *ucp;
  ...
  /* For brevity treating `void *` as the same size as `int` -
     DO NOT USE AS-IS.
     makecontext exposes an annoyingly inconvenient API that only
     accepts int arguments; correct code would deconstruct each
     pointer into two ints (on architectures where pointer is
     larger than int) and reconstruct them in the trampoline. */
  makecontext(ucp, trampoline, 2, (int) cb, (int) arg);
  ...
}

For bonus points, you can modify the trampoline to store the void * value returned by the callback function on the stack and have your equivalent of pthread_join() retrieve it. 为了获得加分,您可以修改蹦床以将回调函数返回的void *值存储在堆栈上,并使pthread_join()等效。

In principle, you can always cast any type of pointer to any other kind of pointer, but for function pointers, I would strongly suggest against . 原则上,您始终可以将任何类型的指针转​​换为任何其他类型的指针,但是对于函数指针,我强烈建议反对

Your thread_func will expect an argument on the stack which will not be provided if invoked after your miscast. 您的thread_func期望在堆栈上有一个参数,如果您在错误地调用之后调用该参数,则不会提供该参数。 Even worse, thread_func will write a return value somewhere where it shouldn't, thus corrupting your stack. 更糟糕的是, thread_func会在不应该写入的地方写入返回值,从而破坏了堆栈。

A solution would be to wrap the invocation in its own function of appropriate type. 一种解决方案是将调用包装在其自己的适当类型的函数中。

You can typecast a function pointer just like a variable. 您可以像变量一样键入函数指针。 The syntax is more awkward, but it's certainly possible (whether it's a good idea is another discussion entirely). 语法比较笨拙,但是肯定是可能的(是否一个好主意,完全是另一个讨论)。

In this case, though, it's probably not what you want to do. 但是,在这种情况下,这可能不是您想要的。 From the man page for swapcontext : swapcontext手册页中

Before invoking makecontext(), the caller must allocate a new stack for this context and assign its address to ucp->uc_stack, 在调用makecontext()之前,调用者必须为此上下文分配一个新的堆栈,并将其地址分配给ucp-> uc_stack,

Your thread function takes an argument. 您的线程函数接受一个参数。 Pass that argument to the new context via the stack you created. 通过创建的堆栈将该参数传递给新上下文。 The function that you pass to makecontext() can be a wrapper function that retrieves the value from the stack and passes it to the thread function as an argument. 传递给makecontext()函数可以是包装函数,该函数从堆栈中检索值并将其作为参数传递给线程函数。 A typecast alone wouldn't provide a method for getting the data in the argument down to the function in the new context. 仅类型转换不会提供一种方法来将参数中的数据获取到新上下文中的函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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