0

我正在尝试创建 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);

我有这个错误!问题是什么 ?!

4

0 回答 0