gpt4 book ai didi

c - 什么是实现简单的基于 clone() 的多线程库的好方法?

转载 作者:太空宇宙 更新时间:2023-11-04 08:56:02 25 4
gpt4 key购买 nike

我正在尝试使用 clone() 和其他内核实用程序基于 Linux 构建简单的多线程库。我已经到了我不确定什么是正确的做事方式的地步。我尝试使用原始 NPTL 代码,但它有点太多了。

这就是我想象的 create 方法:

typedef int sk_thr_id;
typedef void *sk_thr_arg;
typedef int (*sk_thr_func)(sk_thr_arg);


sk_thr_id sk_thr_create(sk_thr_func f, sk_thr_arg a){

void* stack;

stack = malloc( 1024*64 );
if ( stack == 0 ){
perror( "malloc: could not allocate stack" );
exit( 1 );
}

return ( clone(f, (char*) stack + FIBER_STACK, SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM, a ) );


}

1:我不太确定正确的 clone() 标志应该是什么。我刚刚发现这些被用在一个简单的例子中。欢迎在此处提供任何一般说明。

以下是使用 futexes 创建的互斥原语的一部分(暂时不是我自己的代码):

#define cmpxchg(P, O, N) __sync_val_compare_and_swap((P), (O), (N))

#define cpu_relax() asm volatile("pause\n": : :"memory")

#define barrier() asm volatile("": : :"memory")


static inline unsigned xchg_32(void *ptr, unsigned x)
{
__asm__ __volatile__("xchgl %0,%1"
:"=r" ((unsigned) x)
:"m" (*(volatile unsigned *)ptr), "0" (x)
:"memory");

return x;
}


static inline unsigned short xchg_8(void *ptr, char x)
{
__asm__ __volatile__("xchgb %0,%1"
:"=r" ((char) x)
:"m" (*(volatile char *)ptr), "0" (x)
:"memory");

return x;
}



int sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3)
{
return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
}




typedef union mutex mutex;

union mutex
{
unsigned u;
struct
{
unsigned char locked;
unsigned char contended;
} b;
};


int mutex_init(mutex *m, const pthread_mutexattr_t *a)
{
(void) a;
m->u = 0;
return 0;
}

int mutex_lock(mutex *m)
{
int i;

/* Try to grab lock */
for (i = 0; i < 100; i++)
{
if (!xchg_8(&m->b.locked, 1)) return 0;

cpu_relax();
}

/* Have to sleep */
while (xchg_32(&m->u, 257) & 1)
{
sys_futex(m, FUTEX_WAIT_PRIVATE, 257, NULL, NULL, 0);
}

return 0;
}

int mutex_unlock(mutex *m)
{
int i;

/* Locked and not contended */
if ((m->u == 1) && (cmpxchg(&m->u, 1, 0) == 1)) return 0;

/* Unlock */
m->b.locked = 0;

barrier();

/* Spin and hope someone takes the lock */
for (i = 0; i < 200; i++)
{
if (m->b.locked) return 0;

cpu_relax();
}

/* We need to wake someone up */
m->b.contended = 0;

sys_futex(m, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);

return 0;
}

2:我的主要问题是如何实现“join”原语?我知道它也应该基于 futexes。现在想出点什么对我来说很困难。

3:我需要一些方法来在线程完成后清理东西(比如分配的堆栈)。我也想不出这样做的好方法。

可能对于这些,我需要在用户空间中为每个线程添加额外的结构,并在其中保存一些信息。有人可以指出解决这些问题的好方向吗?

4:我希望有一种方法可以告诉线程已经运行了多长时间,自上次安排线程以来已经运行了多长时间以及其他类似信息。是否有一些内核调用提供此类信息?

提前致谢!

最佳答案

可以存在一个“多线程库”作为独立于标准库其余部分的第三方库的想法是一个过时且有缺陷的概念。如果你想这样做,你必须首先放弃对标准库的所有使用;特别是,如果您自己调用 clone,则对 malloc 的调用是完全不安全的,因为:

  1. malloc 不知道存在多个线程,因此可能无法执行正确的同步。

  2. 即使它知道它们存在,malloc 也需要访问一个未指定的、特定于实现的结构,该结构位于线程指针给定的地址。由于此结构是特定于实现的,因此您无法创建这样一个结构,该结构将被系统 libc 的当前版本和所有 future 版本正确解释。

这些问题不仅适用于 malloc,还适用于大多数标准库;即使是异步信号安全函数也可能使用起来不安全,因为它们可能会取消引用线程指针以用于与取消相关的目的、执行最佳系统调用机制等。

如果您真的坚持要实现自己的线程,则必须避免使用 glibc 或任何与线程集成的现代 libc,而是选择更简单的东西,例如 klibc。这可能是一个教育实验,但不适合已部署的应用程序。

关于c - 什么是实现简单的基于 clone() 的多线程库的好方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17019342/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com