Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
实现用户级线程库-从makecontext返回值_C_Multithreading_Ucontext - Fatal编程技术网

实现用户级线程库-从makecontext返回值

实现用户级线程库-从makecontext返回值,c,multithreading,ucontext,C,Multithreading,Ucontext,我看到了一些关于用户线程库的问题,但没有一个能回答我的问题。我可以创建线程、运行线程、取消线程和退出线程。由于某种原因,我不能做的是获取一个线程来返回数据 初始化线程库时,我将退出线程上下文设置如下: getcontext(&threadEnd); threadEnd.uc_stack.ss_sp = (char *)malloc(SIGSTKSZ); threadEnd.uc_stack.ss_size = SIGSTKSZ; makecontext(&threadEnd, (

我看到了一些关于用户线程库的问题,但没有一个能回答我的问题。我可以创建线程、运行线程、取消线程和退出线程。由于某种原因,我不能做的是获取一个线程来返回数据

初始化线程库时,我将退出线程上下文设置如下:

getcontext(&threadEnd);
threadEnd.uc_stack.ss_sp = (char *)malloc(SIGSTKSZ);
threadEnd.uc_stack.ss_size = SIGSTKSZ;
makecontext(&threadEnd, (void *) thread_exit, 1, &ReturnValue);
thread->myContext.uc_stack.ss_sp = (char *) malloc(SIGSTKSZ);
thread->myContext.uc_stack.ss_size = SIGSTKSZ;
thread->myContext.uc_link = &threadEnd;
我创建一个线程并按如下方式分配它:

getcontext(&threadEnd);
threadEnd.uc_stack.ss_sp = (char *)malloc(SIGSTKSZ);
threadEnd.uc_stack.ss_size = SIGSTKSZ;
makecontext(&threadEnd, (void *) thread_exit, 1, &ReturnValue);
thread->myContext.uc_stack.ss_sp = (char *) malloc(SIGSTKSZ);
thread->myContext.uc_stack.ss_size = SIGSTKSZ;
thread->myContext.uc_link = &threadEnd;
当函数返回并调用线程_exit()时:

void thread\u退出(void*retval){
int*测试;
如果(retval!=NULL)
{
test=(int*)retval;
printf(“返回值:%i\n”,*测试);
fflush(stdout);
}
打印输出总是“返回值:0”

被调用函数返回指向整数的指针


我做错了什么?

您需要一些简单的同步来等待一个线程。工作线程设置变量test和signals

// Pseudo code
// worker thread
retval = &VALUE; // retval is pointer?
SignalEvent( hEvent );
以及主线:

// Pseudo code
// main thread
int* test;

hEvent = CreateEvent();

WaitOnEvent( hEvent );

if (retval != NULL)
{
    test = (int*) retval;
    printf("Returned value: %i\n", *test);
    fflush(stdout);
}

和许多线程,你需要决定你是否简单地等待它们中的任何一个,直到它们全部发出信号,或者你要等到所有的信号,然后检查值。(稍微复杂一点的情况)

<>你应该使用C++,我可以提供一个C++ 11条件变量的例子,但是C通常是POSIX或Win32 API,但是我们可以使用伪代码.Win32和。
请注意,当线程完成时,一个线程也会触发信号,因此在Win32中,您可以直接在线程句柄上等待,但这种方法可能不可移植。此外,线程及其同步不是C语言标准的一部分,因此仅适用于提供这两种功能的特定操作系统才有意义。

如果您单步执行程序在GBD makecontext中,不保存用于生成上下文的函数的返回

我的实验示例:(观察rax寄存器):

返回声明时:

thread1 (arg=0x1) at test_create_join.c:14
14      return (void *)11;
Value returned is $1 = 19
(gdb) info registers
rax            0x13 19
---
返回后:

(gdb) step
15  }
(gdb) info registers
rax            0xb  11
内部上下文切换:

__start_context () at ../sysdeps/unix/sysv/linux/x86_64/__start_context.S:32
32  ../sysdeps/unix/sysv/linux/x86_64/__start_context.S: No such file or directory.
(gdb) info registers
rax            0xb  11
您可以看到,对于一些指令,返回值被保留,但经过几步之后,返回值变为0。显然,它特定于x86_64 arch,但我认为它可能与大多数arch相同(即makecontext的行为)

现在,如果您需要线程函数的返回值,您可以采用另一种方法。只需创建一个用于运行线程的线程处理程序,并使用该处理程序创建新上下文。在这里,您可以获取要作为线程运行的函数的返回值,并将其保存在线程控制块结构中供以后使用

typedef struct {
    thread_start_routine start;
    void *arg;
} entry_point;

static void thread_runner(void *args) {
    exit_critical_section();

    entry_point *entry = (entry_point *) args;

    // run the thread and get the exit code
    current->retcode = entry->start(entry->arg);
}

首先,当向
makecontext
提供参数时,最后一个参数应始终为
NULL

makecontext(&threadEnd, (void *) thread_exit, 1, &ReturnValue, NULL);
我也遇到了同样的问题,我处理它的方式有点不同,即我没有使用
uc_link
而是存储
start_例程
,即
func
arg
thread
结构中,并使用了一个包装函数:一个
thread\u runner
,它实际调用线程的函数并存储返回值:

makecontext(&thread->ctx, (void *) thread_runner, 1, thread, NULL);
其中,线程运行器是:

void thread_runner(thread_t *thread){
  void **retval = thread->func(thread->arg);
  if(retval != NULL){
    thread_exit(*retval);
  } else {
    thread_exit(NULL);
  }
}

我们不应该在的参数列表中传递指针。它们必须是手册中指定的整数:

调用函数func,并传递序列 argc后面的整数(int)参数的个数;调用方必须 在argc中指定这些参数的数目


在某些体系结构上,整数与指针大小相同(例如32位),但在另一些体系结构上,指针是64位的,而整数是32位长的。在最近的GLIBC/Linux x86_64体系结构上,参数在上下文中存储为“长”整数。因此,这可能会起作用,因为这会使参数存储为64位值(与指针的大小兼容)但这是不可移植的。因此,这可以解释为什么通过“&ReturnValue”指针无法获得正确的值。

我正在使用上下文切换模拟线程。在这种情况下,“线程”已完成处理,并且由于makecontext中定义的uc_链接而处于线程_exit中。但是,即使我在函数中返回了一个值,我在线程_exit中也看不到该值。无需发出信号,因为我尚未实现先发制人的多任务处理。我最终选择了一个不同的实现。但感谢您尽可能深入地了解这一点。它似乎与文档(或我对它的解释)所说的不符,但与您所发现的相符。这可能是因为不同体系结构之间的行为不一致。