我正在尝试创建 64 个线程,并且我给每个线程 65536 个字节作为堆栈......但是从堆栈的顶部,我需要 64 个字节来存储线程函数参数(前 4 个字节是线程 ID(0 到 63 ),第二个 4 字节是线程消息长度(传递给 ' write()
'),从字节 8 开始,它是由sprintf
(在线程创建之前 ( clone()
)) 创建的线程消息。在每个线程进程的顶部,我使用了:
syscall(SYS_futex, & __THREADS_STATUS[thread_id], FUTEX_WAIT, 0, NULL, NULL, 0);
让线程进入睡眠状态,直到我们用以下命令唤醒它:
syscall(SYS_futex, & __THREADS_STATUS[i], FUTEX_WAKE, 1, NULL, NULL, 0);
当线程唤醒时,它使用锁定方法锁定线程写入进程,然后写入其消息,然后解锁锁定的用户空间......
我们要唤醒 15 个线程一个一个地写他们的消息(这就是为什么我使用了 lock !否则,将不会观察到写的顺序)......
我期望发生的结果:
Thread #0 started
Thread #1 started
Thread #2 started
Thread #3 started
Thread #4 started
Thread #5 started
Thread #6 started
Thread #7 started
Thread #8 started
Thread #9 started
Thread #10 started
Thread #11 started
Thread #12 started
Thread #13 started
Thread #14 started
我得到一个错误!!!!
Thread #0 started
Thread #2 started
Thread #12 started
Thread #11 started
==48072== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==48072== Bad permissions for mapped region at address 0x400BF0
==48072== at 0x400A8D: thread_main (in /tmp/tmp.x9XSQBiKue/cmake-build-release/threads_manager)
==48072== by 0x4F3EDC2: clone (in /usr/lib64/libc-2.28.so)
==48072== by 0x1200000001: ???
==48072== by 0x2320646165726853: ???
==48072== by 0x6574726174732031: ???
==48072== by 0xA63: ???
这是我的源代码(完整):
#define _GNU_SOURCE
#include <sched.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <syscall.h>
#include <sys/mman.h>
#include <linux/futex.h>
#include <stdatomic.h>
#define THREADS_COUNT 64
#define THREAD_STACK_SIZE 65536
#define THREAD_FLAGS (CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_PARENT|CLONE_THREAD|CLONE_IO)
static int thread_main(void * data);
static void thread_lock(int * user_space);
static void thread_unlock(int * user_space);
static int __THREADS_STATUS[THREADS_COUNT];
static int __THREADS_WRITE_LOCK = 1; /* 1 = available */
int
main() {
void * memory;
if((memory = mmap(0, (THREADS_COUNT * THREAD_STACK_SIZE), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
printf("mmap() failed");
return 1;
}
for (int i = 0; i < THREADS_COUNT; i++) {
unsigned long long thread_stack_address = (unsigned long long) memory + THREAD_STACK_SIZE + (i * THREAD_STACK_SIZE) - 64;
/*
* At the end of each stack, we reserve 64 bytes to store:
* [0-4] => thread id
* [4-8] => thread message length to pass to 'write()'
* [8-n] => thread message to pass to 'write()'
*/
(*(int *)(thread_stack_address)) = i;
(*(int *)(thread_stack_address + 4)) = sprintf((char *)(thread_stack_address + 8), "Thread #%d started\n", i);
if(clone(thread_main, (void *) thread_stack_address, THREAD_FLAGS, (void *) thread_stack_address) == -1) {
printf("clone() failed");
munmap(memory, (THREADS_COUNT * THREAD_STACK_SIZE));
return 1;
}
}
for (int i = 0; i < 15; i++) {
syscall(SYS_futex, & __THREADS_STATUS[i], FUTEX_WAKE, 1, NULL, NULL, 0);
}
sleep(3);
munmap(memory, (THREADS_COUNT * THREAD_STACK_SIZE));
return 0;
}
static int
thread_main(void * data) {
int thread_id = (*(int *)(data));
int thread_msg_len = (*(int *)(data + 4));
char * thread_msg = (data + 8);
// Wait to woken up by the main process
syscall(SYS_futex, & __THREADS_STATUS[thread_id], FUTEX_WAIT, 0, NULL, NULL, 0);
// Lock to write then unlock ...
thread_lock(& __THREADS_WRITE_LOCK);
write(0, thread_msg, thread_msg_len);
thread_unlock(& __THREADS_WRITE_LOCK);
return 0;
}
static void
thread_lock(int * user_space) {
while (1) {
static const int one = 1;
if(atomic_compare_exchange_strong(user_space, & one, 0))
break;
syscall(SYS_futex, user_space, FUTEX_WAIT, 0, NULL, NULL, 0);
}
}
static void
thread_unlock(int * user_space) {
static const int zero = 0;
if(atomic_compare_exchange_strong(user_space, & zero, 1)) {
syscall(SYS_futex, user_space, FUTEX_WAKE, 1, NULL, NULL, 0);
}
}
一切似乎都很好!但是因为这些:
thread_lock(& __THREADS_WRITE_LOCK);
write(0, thread_msg, thread_msg_len);
thread_unlock(& __THREADS_WRITE_LOCK);
我有这个错误!问题是什么 ?!