2012-01-04 163 views
2

我想通过一些函数来获取线程的堆栈地址,我们可以通过pthread_self()。可能吗?我这样做的原因是因为我想为自己的堆栈中的某个线程写一个自己分配的线程标识符。我可以在堆栈末尾(堆栈内存的末尾,而不是当前的堆栈地址)写入数据,因此我们可以期望应用程序不会到达堆栈的底部,因此可以使用空间。我可以从pthread_self()获得一个线程的堆栈地址()

换句话说,我想使用线程堆栈来放置一种线程局部变量。那么,我们是否有像pthread提供的以下功能?

stack_address = stack_address_for_thread(pthread_self()); 

我可以使用gcc的线程局部变量的语法来达到这个目的,但我处于无法使用它们的状态。

+1

你会如何使用这样的地址?在C语言中,“堆栈”的地址不是很好定义,因为语言本身不需要使用堆栈。即使您知道架构使用堆栈,线程的当前帧将随着线程调用并返回函数而一直改变。 – unwind 2012-01-04 15:35:21

+0

uwind,我同意,但是就像我说过的,我可以将我的变量放置在栈底的某处。到最后,我的意思是分配堆栈的结束。所以,如果我们有1 MB的堆栈,我可以把它放下1MB。我知道它的骇人听闻,但我们可以预料,一个应用程序不太可能陷入堆栈底部,并且几个字节将永远保持空闲状态。 – MetallicPriest 2012-01-04 15:38:42

+0

@MetallicPriest:尽管如此,为什么?我喜欢这个问题,但仍然奇怪为什么你不能将数据存储在更容易访问(更安全)的地方。 – 2012-01-04 15:41:01

回答

-2

首先得到堆栈的底部,并给它的读/写权限以下面的代码。

pthread_attr_t attr; 
void * stackaddr; 
int * plocal_var; 
size_t stacksize; 

pthread_getattr_np(pthread_self(), &attr); 
pthread_attr_getstack(&attr, &stackaddr, &stacksize); 

printf("stackaddr = %p, stacksize = %d\n", stackaddr, stacksize); 

plocal_var = (int*)mmap(stackaddr, 4096, PROT_READ | PROT_WRITE, 
      MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 
// Now try to write something 
*plocal_var = 4; 

,然后你可以得到线程ID,与功能get_thread_id(如下图所示)。请注意,调用大小为4096的mmap会将栈的边界压入4096,这就是为什么我们在获取局部变量地址时减去4096的原因。

int get_thread_id() 
{ 
    pthread_attr_t attr; 
    char * stackaddr; 
    int * plocal_var; 
    size_t stacksize; 

    pthread_getattr_np(pthread_self(), &attr); 
    pthread_attr_getstack(&attr, (void**)&stackaddr, &stacksize); 

    //printf("stackaddr = %p, stacksize = %d\n", stackaddr, stacksize); 

    plocal_var = (int*)(stackaddr - 4096); 

    return *plocal_var; 
} 
+1

如果你不能使用线程本地化,那你认为'pthread_getattr_np' * *会起作用吗? – 2012-01-04 15:59:10

+0

这真的很不好,而且会依赖于你的堆栈的特定数据布局。在标准和工具中提供了线程专用存储的方法,使用它们。 – 2012-01-04 16:32:55

+1

通过使用MAP_FIXED,您可以运行发生映射的任何事情的重大风险。充其量,这是一个不完美的解决方案。 – 2012-01-04 18:05:42

6

可能最好使用pthread_key_createpthread_key_getspecific,让实施担心这些细节。

使用的一个很好的例子是在这里:

pthread_key_create

编辑:我要澄清 - 我建议你使用创建线程本地信息的libpthread提供的方法,而不是滚动您自己把东西推到堆栈的尽头,可能会丢失信息。

2

随着GCC,它是简单的声明你的线程局部变量与__thread关键字,像

__thread int i; 
    extern __thread struct state s; 
    static __thread char *p; 

也就是说GCC具体的(但我会猜clang有它也,和最新的C++ &未来的C标准具有比基于指针黑客类似的东西),但不脆upeon pthread_self()(应该是有点快,但移植性较差,比pthread_key_getsspecific,为suggested by Denniston

但我真的很喜欢你给更多的背景和motivat在你的问题离子。

+0

是的Basile,我知道如何在gcc中创建线程局部变量,但正如我在我的问题中所说的,我不能在这里使用它们。 – MetallicPriest 2012-01-04 15:52:28

+0

你应该解释为什么你不能使用它们。你应该解释为什么你的解决方案更好(我不这么认为)。 – 2012-01-04 15:54:23

+1

线程本地存储'_Thread_local'也是C11附带的一个新特性,它实际上等同于这个gcc扩展。所以在gcc中使用这个特性是未来的证明。 – 2012-01-04 16:29:48

2

我想写我自己的分配线程标识的线程

有多种方式来实现这一目标。最明显的一个:

__thread int my_id; 

我可以通过gcc的使用线程局部变量的语法用于此目的,但我的情况,我可以不使用它们。

你需要说明的是为什么你不能使用线程本地。其他解决方案(如pthread_getattr_np)也无法正常工作的可能性很高。

相关问题