стек и vtable [re] местоположение - PullRequest
3 голосов
/ 05 февраля 2011

ПРИМЕЧАНИЕ: Чтобы понять мой вопрос, вам может нужно узнать о моем проекте и проблеме. Если нет, перейдите вправо к разделу «ВОПРОС» внизу.

<ч /> ПРОЕКТ

Я работаю над написанием класса C ++, который позволяет его родителю вести себя как синхронные / блокирующие потоки, используя Pause () и Resume ().

Вот пример того, как это будет работать.

class BlockingThread
   : public BlockingThreadBase // all the Asm magic happens in BlockingThreadBase
{
  void StartStopHere(void) // called upon the first Resume() call (pure virtual in base)
  {
    printf("1"); Pause();
    printf("3"); Pause();
    printf("5"); Pause();
  }
};

int main(void)
{
  BlockingThread obj;

  obj.Resume(); printf("2");
  obj.Resume(); printf("4");
  obj.Resume(); printf("6");

  return 0;
}

// OUTPUT: 123456

Я пробовал настоящую многопоточность и несколько новых идей, но они оказались слишком медленными для передачи между местами кода 21 миллион раз в секунду.

Моя последняя идея - использовать куски стека (буферы стека) для создания иллюзии нескольких стеков. Когда вызывается obj1.Resume (), он возвращается в местоположение своего личного стека, New #1 Stack, выполняется до Pause (), а затем возвращается в предыдущее положение стека, в котором он находился.

<ч /> ИЛЛЮСТРАЦИИ

Как будет выглядеть стек без BlockingThread объектов в main ().

 _________________
| Normal | Stack  |
| Stack  | Buffer |
|________|________|

Как будет выглядеть BlockingThread объект в main () в стеке.

 ___________________________________
| Normal | Stack  | New #1 | Stack  |
| Stack  | Buffer | Stack  | Buffer |
|________|________|________|________|

Как два BlockingThread объекта в main () будут выглядеть в стеке.

 _____________________________________________________
| Normal | Stack  | New #1 | Stack  | New #2 | Stack  |
| Stack  | Buffer | Stack  | Buffer | Stack  | Buffer |
|________|________|________|________|________|________|

<ч /> ПРОБЛЕМА

При перемещении в «новый» стек и последующем вызове obj.Resume () (из main), который, в свою очередь, вызывает StartStopHere (), вызывает segfault в точке вызова StartStopHere (). GDB говорит can't find linker symbol for virtual table for 'BlockingThreadBase' value, когда я пытаюсь получить значение переменной-члена из BlockingThreadBase. Вот почему я подозреваю, что у него такая же проблема при попытке найти местоположение StartStopHere (), когда он вызывается.

<ч /> ВОПРОС

(игнорируйте слова, выделенные курсивом, если вы не читали другие разделы)

Как найти [ и переместить или скопировать ] виртуальную таблицу (или ее местоположение, если она хранится) класса в стеке [ normal ] [ в новый стек ]?

Ответы [ 2 ]

1 голос
/ 01 июля 2011

Я предполагаю, что магия вашего проекта происходит через какую-то магию сборки.Это очевидно подразумевает, что это будет зависеть от архитектуры.Чтобы проверить, как получить доступ к vtable (или vpointer) к классу из сборки, лучше всего просто проверить, как это делает компилятор при доступе к виртуальному методу, - просто отключить ваш код и посмотреть.На x86 linux g ++ скопированной программе, которую я тестировал - первые четыре байта объекта - это указатель на таблицу (выделенную статически, я думаю) виртуальных функций.поскольку разные архитектуры могут использовать разные подходы к vtables.Поэтому я не ожидал бы, что у c ++ будут какие-либо средства для этого.

Так много о вашем вопросе.Тем не менее, я думаю, что если простой memcpy (& BlockingThread, sizeof (BlockingThread)) не работает, то вы сможете скопировать немного больше.

1 голос
/ 05 февраля 2011

Я думаю, что вы ищете совместную работу с потоками.Для быстрой и простой реализации, посмотрите libco.http://byuu.org/files/libco_v16.tar.bz2. Коммутация реализована в необработанной сборке и работает для x86, x86_64, PPC32 и PPC64.Он также имеет реализацию (ab) с использованием setjmp / longjmp и posix ucontext (очень медленно).Накладные расходы при этом виде стека колеблются примерно в 5 раз.20 миллионов обменов в секунду должны работать нормально.Для проверки скорости включены некоторые тестовые программы.

Пример:

#include "libco.h"
#include <stdio.h>

static cothread_t t1;
static cothread_t t2;

static void foo(void)
{
   for (int i = 1; i < 10; i+=2)
   {
      printf("%d\n", i);
      co_switch(t1); // Swap back to main cothread
   }
}

int main(void)
{
   // Get a handle to the current coinstance.
   t1 = co_active();

   t2 = co_create(10000, foo); // New cothread with stacksize 10000.

   for (int i = 0; i < 10; i+=2)
   {
      printf("%d\n", i);
      co_switch(t2); // Swap to cothread t2.
   }

   co_delete(t2);
}
...