Как мне написать в стек другого потока в C / C ++? - PullRequest
0 голосов
/ 30 октября 2009

Я знаю, что это плохая идея!Конечно, для безопасного программирования стек для данного потока следует считать закрытым для этого потока.Но POSIX, по крайней мере, гарантирует, что вся память потока является общей и доступной для записи для других потоков, что означает, что стек одного потока может (теоретически) быть записан другим потоком.Поэтому мне любопытно, как можно это сделать.

Единственный способ, которым я могу придумать, - это передать адрес локальной переменной в потоке B в поток A и начать запись в эту общую область.Но это не полностью эмулирует вызовы функций в C. В частности, мне любопытно, можно ли сказать, иметь поток A sleep, когда его программный счетчик установлен на первую строку некоторой функции, которая принимает параметры, а затем в потоке Bфактически помещаем эти параметры в стек, затем возобновляем поток A и выполняем его так, как если бы функция была первоначально вызвана в потоке A с этими параметрами.Я думаю, что для этого требуется, чтобы поток B имел доступ к регистрам потока A по крайней мере по соглашениям о вызовах x86, и я не уверен, что это возможно.

Ответы [ 3 ]

2 голосов
/ 30 октября 2009

Хорошо, поэтому один из способов доступа к стеку потока - это выделить память стека самостоятельно и назначить ее при создании потока. Это может быть достигнуто с помощью 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);
    }

Дайте нам знать, если это то, что вы хотели. Извините за плохой отступ и стиль кодирования.

1 голос
/ 30 октября 2009

Может потребоваться передать указатель на локальную переменную volatile в функции foo() в потоке A в функцию bar() в потоке B, а затем позволить потоку B изменить его содержимое.

Но, учитывая оптимизацию и кэширование памяти потоков, невозможно гарантировать, что это будет работать.

Так что, да, это, вероятно, плохая идея. почему ты хочешь сделать это? семафоры или мьютексы были бы лучшим решением?

0 голосов
/ 30 октября 2009

Похоже, вы пытаетесь реализовать свой собственный (быстрый) мьютекс пространства пользователя, так почему бы не изучить просто использование futex ?Они могут быть хитрыми , но, по крайней мере, у вас (в крайнем случае) есть ядро ​​для арбитража рас.

То, что предложил Loadmaster , может работать, с двумя потоками,Больше двух, и будет очень, очень неприглядно.Кроме того, я повторяю то, что он сказал о волатильности, которая не всегда волатильна.

...