0

I know this is a bad idea! Certainly for safe programming the stack for a given thread should be considered private to that thread. But POSIX at least guarantees that all of a thread's memory is shared and writeable by other threads, which means the stack of one thread can (in theory) be written to by another thread. So I'm curious how one could do that.

The only way I can think of would be to pass the address of a local variable in thread B to thread A and have A start writing to that general area. But this doesn't fully emulate function calls in C. In particular I'm curious if it's possible to say, have thread A sleep while its program counter is set to the first line of some function that takes parameters, and then on thread B actually push those parameters onto the stack, then resume thread A and have it execute as if the function were originally called in thread A with those parameters. I think this requires thread B to be able to access thread A's registers under at least x86 calling conventions, and I'm not sure that's possible.

4

3 回答 3

2

好的,访问线程堆栈的一种方法是自己分配堆栈内存并在创建线程时分配它。这可以通过pthread_attr_setstack()调用来实现。

以下代码将线程堆栈设置为手动分配的内存(此处为 malloc),而不是系统分配它。稍后您可以在创建线程后访问 mystack 指针。此类代码的一个用例是,您可以转储线程堆栈以获取其快照,然后您可以恢复该线程。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <limits.h>

   void *thread(void *arg) {
      char *ret;
      printf("thread() entered with argument '%s'\n", (char *)arg);
      if ((ret = (char*) malloc(20)) == NULL) {
        perror("malloc() error");
        exit(2);
      }
      strcpy(ret, "This is a test");
      pthread_exit(ret);
    }

    int main(void)
    {
       pthread_attr_t attr;
       int              rc;

      pthread_t thid;
      void *ret;

       void  *mystack;
       size_t mystacksize = 2 * PTHREAD_STACK_MIN;

       if (pthread_attr_init(&attr) == -1) {
          exit(1);
       }

       /* Get a big enough stack and align it on 4K boundary. */
       mystack = malloc(PTHREAD_STACK_MIN * 3);
       if (mystack != NULL) {
          printf("Using PTHREAD_STACK_MIN to align stackaddr %x.\n", mystack);
          mystack = (void *)((((long)mystack + (PTHREAD_STACK_MIN - 1)) /
                              PTHREAD_STACK_MIN) * PTHREAD_STACK_MIN);
       } else {
          exit(2);
       }

       printf("Setting stackaddr to %x\n", mystack);
       printf("Setting stacksize to %x\n", mystacksize);
       rc = pthread_attr_setstack(&attr, mystack, mystacksize);
       if (rc != 0) {
          printf("pthread_attr_setstack returned: %d\n", rc);
          exit(3);
       } else {
          printf("Set stackaddr to %x\n", mystack);
          printf("Set stacksize to %x\n", mystacksize);
       }


      if (pthread_create(&thid, &attr, thread, "thread 1") != 0) {
        exit(1);
      }

      if (pthread_join(thid, &ret) != 0) {
        exit(3);
      }

      printf("thread exited with '%s'\n", ret);
       rc = pthread_attr_destroy(&attr);
       if (rc != 0) {
          exit(5);
       }

       exit(0);
    }

让我们知道这是否是您想要的。抱歉缩进和编码风格不好。

于 2009-10-30T14:31:44.190 回答
1

It might work to pass a pointer to a volatile local variable in function foo() in thread A to function bar() in thread B, and then letting thread B modify its contents.

But in the face of optimization and thread memory caching, there is no way to guarantee that this will work.

So, yes, this is probably a bad idea. Why do you want to do this? Would semaphores or mutexes be a better solution?

于 2009-10-29T23:30:38.600 回答
0

看起来您正在尝试实现自己的(快速)用户空间互斥锁,那么为什么不简单地使用futex进行探索呢?它们可能很棘手,但至少你(作为最后的手段)有内核来仲裁比赛。

可以想象,Loadmaster 的建议可以使用两个线程超过两个,它会变得非常非常恶心。此外,我支持他所说的易变并不总是易变的说法。

于 2009-10-30T02:14:47.243 回答