Linux 克隆 "kills" 主线程
Linux Clone "kills" main thread
我正在 尝试 在 Linux 上用 C 语言实现线程(显然是使用 clone()),但我遇到了一个奇怪的问题。
首先,这是我的互斥函数:
void mutex_lock(int* lock) {
while (!__sync_bool_compare_and_swap(lock, 0, 1)) {
syscall(SYS_futex, lock, FUTEX_WAIT_PRIVATE, 1, NULL, NULL, 0);
}
}
void mutex_unlock(int* lock) {
if (__sync_bool_compare_and_swap(lock, 1, 0)) {
syscall(SYS_futex, lock, FUTEX_WAKE_PRIVATE, 0, NULL, NULL, 0);
}
}
还有我的线程结构
typedef int (*ThreadCallback)(void*);
typedef struct Thread {
void* alloc;
char lockSpace[sizeof(int) * 2]; /* Used to align lock pointer properly */
int* lock;
int started;
int tid;
void* stack;
size_t stackSize;
ThreadCallback fn;
void* args;
}* Thread;
在我的代码中,我分配并初始化了一个 Thread 结构,稍后将使用
void* start = memAllocThread(sizeof(void*) + sizeof(struct Thread) + TH_STACK_SIZE);
if (start == NULL) {
return TH_MEM;
}
struct Thread* th = start + TH_STACK_SIZE + sizeof(void*);
th->alloc = start;
size_t lockSpacePtr = (size_t)(th->lockSpace);
lockSpacePtr += 4 - ((lockSpacePtr % 4) % 4); /* To align ptr on? at? 4 bytes */
th->lock = (int*)lockSpacePtr;
*th->lock = 0;
th->started = 0;
th->stack = start + TH_STACK_SIZE;
th->stackSize = TH_STACK_SIZE;
th->fn = fn;
th->args = args;
其中"TH_STACK_SIZE"、"fn"和"args"分别为“0x7fff”"ThreadCallback"和"void*"
现在我已经初始化了 Thread 结构,我用一个输入通道和零个输出通道初始化了 PortAudio 和默认流。然后我开始我的话题
THResult thStart(struct Thread* th) {
int tid;
mutex_lock(th->lock);
if (th->started) {
mutex_unlock(th->lock);
return TH_RUNNING;
}
tid = clone(_thFunction, th->stack, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_IO | CLONE_SIGHAND | CLONE_THREAD, th);
if (tid < 0) {
mutex_unlock(th->lock);
return TH_CLONE_ERRNO;
}
th->started = 1;
th->tid = tid;
mutex_unlock(th->lock);
return TH_OK;
}
"int _thFunction(void*)"当前为空(填充时应该是th->fn开始,不过这里没问题)
现在,在调用 Pa_StartStream() 之后,我可以写任何我想写的东西,它不会被执行(顺便说一句,如果我在代码中散布一些内容,printf 就会变得疯狂)。
- 我尝试追踪段违规
- 我删除了 Pa_StartStream : 它起作用了,但 printf 仍然太疯狂了
- 我删除了线程的开头,一切正常
有什么想法吗?
编辑 1:
- 当创建的线程结束时,程序结束
- gdb 对此什么也没说,我试过分解来分析堆栈但没有错
关于这个问题,有两点很突出。
1) 试图从 ad-hoc 克隆调用 printf。很可能 standard-library 垃圾挡在路上。
2) 仅提供4k堆栈。
将 printf(...)
替换为 write(2, ...)
调用,看看是否有更好的行为。你的手仍然会头疼,但它不会立即从你下面消失。
或者试试 gdb
exit()
退出所有线程。也许您需要以其他方式退出。从生成的线程函数返回是个坏主意,因为这会占用主线程的堆栈。
我大概明白为什么它不起作用了。
我读到了 errno
如何是线程安全的,我认为这是因为 pthread
s 创建了线程局部变量(由 (g)libc 使用),而我的实现却没有。
我正在 尝试 在 Linux 上用 C 语言实现线程(显然是使用 clone()),但我遇到了一个奇怪的问题。
首先,这是我的互斥函数:
void mutex_lock(int* lock) {
while (!__sync_bool_compare_and_swap(lock, 0, 1)) {
syscall(SYS_futex, lock, FUTEX_WAIT_PRIVATE, 1, NULL, NULL, 0);
}
}
void mutex_unlock(int* lock) {
if (__sync_bool_compare_and_swap(lock, 1, 0)) {
syscall(SYS_futex, lock, FUTEX_WAKE_PRIVATE, 0, NULL, NULL, 0);
}
}
还有我的线程结构
typedef int (*ThreadCallback)(void*);
typedef struct Thread {
void* alloc;
char lockSpace[sizeof(int) * 2]; /* Used to align lock pointer properly */
int* lock;
int started;
int tid;
void* stack;
size_t stackSize;
ThreadCallback fn;
void* args;
}* Thread;
在我的代码中,我分配并初始化了一个 Thread 结构,稍后将使用
void* start = memAllocThread(sizeof(void*) + sizeof(struct Thread) + TH_STACK_SIZE);
if (start == NULL) {
return TH_MEM;
}
struct Thread* th = start + TH_STACK_SIZE + sizeof(void*);
th->alloc = start;
size_t lockSpacePtr = (size_t)(th->lockSpace);
lockSpacePtr += 4 - ((lockSpacePtr % 4) % 4); /* To align ptr on? at? 4 bytes */
th->lock = (int*)lockSpacePtr;
*th->lock = 0;
th->started = 0;
th->stack = start + TH_STACK_SIZE;
th->stackSize = TH_STACK_SIZE;
th->fn = fn;
th->args = args;
其中"TH_STACK_SIZE"、"fn"和"args"分别为“0x7fff”"ThreadCallback"和"void*"
现在我已经初始化了 Thread 结构,我用一个输入通道和零个输出通道初始化了 PortAudio 和默认流。然后我开始我的话题
THResult thStart(struct Thread* th) {
int tid;
mutex_lock(th->lock);
if (th->started) {
mutex_unlock(th->lock);
return TH_RUNNING;
}
tid = clone(_thFunction, th->stack, CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_IO | CLONE_SIGHAND | CLONE_THREAD, th);
if (tid < 0) {
mutex_unlock(th->lock);
return TH_CLONE_ERRNO;
}
th->started = 1;
th->tid = tid;
mutex_unlock(th->lock);
return TH_OK;
}
"int _thFunction(void*)"当前为空(填充时应该是th->fn开始,不过这里没问题)
现在,在调用 Pa_StartStream() 之后,我可以写任何我想写的东西,它不会被执行(顺便说一句,如果我在代码中散布一些内容,printf 就会变得疯狂)。
- 我尝试追踪段违规
- 我删除了 Pa_StartStream : 它起作用了,但 printf 仍然太疯狂了
- 我删除了线程的开头,一切正常
有什么想法吗?
编辑 1:
- 当创建的线程结束时,程序结束
- gdb 对此什么也没说,我试过分解来分析堆栈但没有错
关于这个问题,有两点很突出。
1) 试图从 ad-hoc 克隆调用 printf。很可能 standard-library 垃圾挡在路上。
2) 仅提供4k堆栈。
将 printf(...)
替换为 write(2, ...)
调用,看看是否有更好的行为。你的手仍然会头疼,但它不会立即从你下面消失。
或者试试 gdb
exit()
退出所有线程。也许您需要以其他方式退出。从生成的线程函数返回是个坏主意,因为这会占用主线程的堆栈。
我大概明白为什么它不起作用了。
我读到了 errno
如何是线程安全的,我认为这是因为 pthread
s 创建了线程局部变量(由 (g)libc 使用),而我的实现却没有。