我正在尝试模拟线程 swapcontext() 等,但我有一些问题:
- 回调函数未运行
- 我从 free() 中收到内存错误: free():无效大小 已中止
- 如何等待所有线程完成?
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <stdarg.h>
#define STACK_SIZE 1024
typedef struct thread {
ucontext_t context;
void* stack;
int done;
} thread_t;
thread_t thread1, thread2;
void thread1_function(int argc, ...) {
va_list args;
va_start(args, argc);
for (int i = 0; i < 10; i++) {
printf("Thread 1 count: %d\n", i);
swapcontext(&thread1.context, &thread2.context);
}
thread1.done = 1;
printf("Thread 1 done\n");
va_end(args);
}
void thread2_function() {
for (int i = 0; i < 10; i++) {
printf("Thread 2 count: %d\n", i);
swapcontext(&thread2.context, &thread1.context);
}
printf("Thread 2 done\n");
thread2.done = 1;
}
int main() {
// Allocate stacks for each thread
thread1.stack = malloc(STACK_SIZE);
thread2.stack = malloc(STACK_SIZE);
// Initialize the execution context for each thread
getcontext(&thread1.context);
thread1.context.uc_stack.ss_sp = thread1.stack;
thread1.context.uc_stack.ss_size = STACK_SIZE;
makecontext(&thread1.context, (void (*)())thread1_function, 1, 2, 0);
getcontext(&thread2.context);
thread2.context.uc_stack.ss_sp = thread2.stack;
thread2.context.uc_stack.ss_size = STACK_SIZE;
makecontext(&thread2.context, (void (*)())thread2_function, 0);
// Switch to thread1
swapcontext(&thread1.context, &thread2.context);
// Free stacks
free(thread1.stack);
free(thread2.stack);
return 0;
}
当我运行代码时,应该运行我的回调函数,而不是出现以下错误并且根本没有该函数(据我所知):
线程 2 计数:0 free():无效大小 已中止
最佳答案
在我的测试中,STACK_SIZE
必须设置为至少 6 KB,否则我会收到错误消息 free(): invalid size
或段错误。因此,我建议将 STACK_SIZE
设置为至少 32 KB,以便合理确定堆栈大小足够。
在您发布的代码中,您设置了
thread1.context
运行函数thread1_function
和thread2.context
运行函数thread2_function
。
但是,在行
swapcontext(&thread1.context, &thread2.context);
在函数 main
中,您使用当前上下文覆盖 thread1.context
并执行 thread2.context
。这意味着 thread1.context
不再设置为执行函数 thread1_function
,而是设置为执行 main
的其余部分。
因为您现在正在执行thread2.context
,所以函数thread2_function
将被执行。该函数将首先打印
Thread 2 count: 0
然后它将执行这一行:
swapcontext(&thread2.context, &thread1.context);
如前所述,thread1.context
不再设置为执行函数 thread1_function
,而是设置为执行 main< 的其余部分
。因此,在调用 swapcontext
后,程序将执行 main
中的以下几行:
// Free stacks
free(thread1.stack);
free(thread2.stack);
return 0;
这些行将终止程序,导致不打印任何其他内容。
为了解决此问题,您不应将 main
的上下文存储在 thread1.context
中。它应该存储在一个单独的对象中。
此外,如果您没有将 thread1.context.uclink
和 thread2.context.uclink
的值设置为非零值,那么程序将thread1_function
或 thread2_function
返回后立即终止。
一种可能的解决方案是将成员uclink
设置为正在执行函数main
的上下文。如果两个线程都完成,则可以将函数 main
编程为终止,否则它将把上下文设置为尚未完成的线程。
另一个问题是该行
swapcontext(&thread1.context, &thread2.context);
如果线程 2 已经完成,则函数 thread1_function
中的内容没有意义,因为在这种情况下,将上下文设置为线程 2 将导致线程 2 重复其最终时间片(堆栈已经被线程2的最后一个时间片使用,可能导致程序崩溃)。
因此,该行应更改为
if ( !thread2.done ) {
swapcontext(&thread1.context, &thread2.context);
}
函数thread2_function
也有同样的问题。
这是一个修复上述所有错误的解决方案:
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <stdarg.h>
#define STACK_SIZE 32768
typedef struct thread {
ucontext_t context;
void* stack;
int done;
} thread_t;
thread_t thread1, thread2;
ucontext_t main_context;
void thread1_function(int argc, ...) {
va_list args;
va_start(args, argc);
for (int i = 0; i < 10; i++) {
printf("Thread 1 count: %d\n", i);
if ( !thread2.done ) {
swapcontext(&thread1.context, &thread2.context);
}
}
thread1.done = 1;
printf("Thread 1 done\n");
va_end(args);
}
void thread2_function() {
for (int i = 0; i < 10; i++) {
printf("Thread 2 count: %d\n", i);
if ( !thread1.done ) {
swapcontext(&thread2.context, &thread1.context);
}
}
printf("Thread 2 done\n");
thread2.done = 1;
}
int main() {
// Allocate stacks for each thread
thread1.stack = malloc(STACK_SIZE);
thread2.stack = malloc(STACK_SIZE);
// Initialize the execution context for each thread
getcontext(&thread1.context);
thread1.context.uc_stack.ss_sp = thread1.stack;
thread1.context.uc_stack.ss_size = STACK_SIZE;
thread1.context.uc_link = &main_context;
makecontext(&thread1.context, (void (*)())thread1_function, 1, 2, 0);
getcontext(&thread2.context);
thread2.context.uc_stack.ss_sp = thread2.stack;
thread2.context.uc_stack.ss_size = STACK_SIZE;
thread2.context.uc_link = &main_context;
makecontext(&thread2.context, (void (*)())thread2_function, 0);
// Switch to thread1
swapcontext( &main_context, &thread1.context );
// If a thread is still running, set context to that thread
if ( !thread1.done ) {
setcontext( &thread1.context );
}
if ( !thread2.done ) {
setcontext( &thread2.context );
}
// Free stacks
free(thread1.stack);
free(thread2.stack);
return 0;
}
该程序有以下输出:
Thread 1 count: 0
Thread 2 count: 0
Thread 1 count: 1
Thread 2 count: 1
Thread 1 count: 2
Thread 2 count: 2
Thread 1 count: 3
Thread 2 count: 3
Thread 1 count: 4
Thread 2 count: 4
Thread 1 count: 5
Thread 2 count: 5
Thread 1 count: 6
Thread 2 count: 6
Thread 1 count: 7
Thread 2 count: 7
Thread 1 count: 8
Thread 2 count: 8
Thread 1 count: 9
Thread 2 count: 9
Thread 1 done
Thread 2 done
关于c - 为什么我的函数没有运行并出现无效内存错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75513673/