RAII, scope(exit) ...;
От: c-smile Канада http://terrainformatica.com
Дата: 18.08.10 21:44
Оценка: -1
Про RAII вопрос имею.

Скажем есть две функции
void enter(CTX& ctx);
void leave(CTX& ctx);

где CTX есть некий объект структруа которого в данном контексте не важна.

Есть также большой набор функций с сигнатурами
void do_something(CTX& ctx, ....);


В каждой такой функции при входе нужно звать enter и соотв. при выходе (любом) leave.
Т.е. примерно так:
void do_something(CTX& ctx, ....)
{
  enter(ctx);  
  ...
  if(cond) { leave(ctx); return; }
  ...
  leave(ctx);
}


В классике это все делается путем RAII helper class:

struct context 
{
  CTX& ctx;
  context(CTX& c):ctx(c) { enter(ctx); }
  ~context() { leave(ctx); }
}


Ну и соответсвенно:

void do_something(CTX& ctx, ....)
{
  context _(ctx);  
  ...
  if(cond) return;
  ...
}


Вопрос состоит в следующем:

Каждая переменная типа context содержит ссылку (указатель de facto) на CTX увеличивая тем самым размер стека функции.
Можно ли как-нибудь избавитсься от этой context::ctx переменной?

Скажем в D я бы написал это как:

void do_something(CTX& ctx, ....)
{
  enter(ctx); scope(exit) leave(ctx);
  ...
  if(cond) return;
  ...
}


Т.е. без "прикапывания" (дублирования) ctx на стеке.

Уверен что в C++ такой кунштюк не сделать но вдруг? Например средствами C++0x ...
Re: RAII, scope(exit) ...;
От: remark Россия http://www.1024cores.net/
Дата: 18.08.10 21:58
Оценка: 38 (1)
Здравствуйте, c-smile, Вы писали:

struct context 
{
  static thread_local CTX* ctx;
  context(CTX& c)
  {
    assert(ctx == 0);
    ctx = &c;
    enter(&c);
  }
  ~context()
  {
    assert(ctx != 0);
    leave(ctx);
    ctx = 0;
  }
};



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


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: RAII, scope(exit) ...;
От: alexeiz  
Дата: 18.08.10 22:01
Оценка: 21 (2) +1
Здравствуйте, c-smile, Вы писали:

CS>Вопрос состоит в следующем:


CS>Каждая переменная типа context содержит ссылку (указатель de facto) на CTX увеличивая тем самым размер стека функции.

CS>Можно ли как-нибудь избавитсься от этой context::ctx переменной?

Компилятор может съоптимизировать это дело и не использовать дополнительный стек.

CS>Скажем в D я бы написал это как:


CS>
CS>void do_something(CTX& ctx, ....)
CS>{
CS>  enter(ctx); scope(exit) leave(ctx);
CS>  ...
CS>  if(cond) return;
CS>  ...
CS>}
CS>


CS>Т.е. без "прикапывания" (дублирования) ctx на стеке.


Ты уверен, что D ничего не кладёт на стек?

В любом случае, попробуй так:
void do_something(context ctx, ...) // by value, context ctor should be implicit
{...
Re: RAII, scope(exit) ...;
От: Erop Россия  
Дата: 18.08.10 22:03
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Уверен что в C++ такой кунштюк не сделать но вдруг? Например средствами C++0x ...




Ну, как вариант, передавать в функцию не ссылку, а тот самый контекст...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: RAII, scope(exit) ...;
От: c-smile Канада http://terrainformatica.com
Дата: 18.08.10 22:47
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, c-smile, Вы писали:


R>
R>struct context 
R>{
R>  static thread_local CTX* ctx;
R>  context(CTX& c)
R>  {
R>    assert(ctx == 0);
R>    ctx = &c;
R>    enter(&c);
R>  }
R>  ~context()
R>  {
R>    assert(ctx != 0);
R>    leave(ctx);
R>    ctx = 0;
R>  }
R>};
R>


Как я понимаю thread_local __declspec(thread) либо __thread ?
Если да то во всяком случае __declspec(thread) даже между разными windows не portable.
User comment в http://msdn.microsoft.com/en-us/library/9w1sdazb(v=VS.80).aspx

А так в принципе как вариант оченно даже ...

А вот интересно какова цена доступа к __declspec(thread) переменной?
TLS как-нибудь через регистры процессора адресуется?
Re[2]: RAII, scope(exit) ...;
От: c-smile Канада http://terrainformatica.com
Дата: 18.08.10 23:01
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Здравствуйте, c-smile, Вы писали:


CS>>Вопрос состоит в следующем:


CS>>Каждая переменная типа context содержит ссылку (указатель de facto) на CTX увеличивая тем самым размер стека функции.

CS>>Можно ли как-нибудь избавитсься от этой context::ctx переменной?

A>Компилятор может съоптимизировать это дело и не использовать дополнительный стек.


Теоретически может но хотелось бы определенной определенности.
Re[2]: RAII, scope(exit) ...;
От: c-smile Канада http://terrainformatica.com
Дата: 19.08.10 03:15
Оценка:
Здравствуйте, Erop, Вы писали:

E>Ну, как вариант, передавать в функцию не ссылку, а тот самый контекст...


Конструктор будет создаваться до входа в функцию (например до инициализхации всех остальных параметров) и соотв. после завершения функции (с этим еще можно жить).

На самом деле enter(CTX& ctx, ...) имеет ряд доп. параметров инициализируемых объектами в scope.

На самом деле это всё для TIScript. Вот реальный пример функции скрипта
Array.map( callback:function [,this_for_callback:object] )


Вызов protect() это именно то что хотелось сделать с пом. RAII.

protect в данном случае регистрирует адреса переменных на C стеке ибо
в строчках с //GC!! может произойти GC и соотв. vector например может переехать на новое место.

static value CSF_map(VM *c)
{
    value vector = 0 ,cmpf = 0, cmpf_this = 0, r_vector = 0;

    protect(c,vector,cmpf,cmpf_this, r_vector); // <<<<<<<< let GC to know about the locations.

    CsParseArguments(c,"V=*V=|V",&vector,&CsVectorDispatch,&cmpf,&CsMethodDispatch,&cmpf_this);

    FETCH(c, vector); // GC!!

    int_t d = CsVectorSize(c,vector);

    r_vector = CsMakeVector(c,d); // GC!!

    int_t ndst = 0;
    if(cmpf_this)
    {
      for( int n = 0; n < d; ++n )
      {
        value r = CsCallMethod(c,cmpf_this, cmpf, cmpf_this, 3, // GC!!
           CsVectorElement(c,vector,n), 
           CsMakeInteger(n),
           vector);
        if( r == NOTHING_VALUE )
          continue;
        CsSetVectorElement(c,r_vector,ndst++,r);
      }
    }
    ....
}


Пока пробую выкрутиться без применения RAII ...
Re[3]: RAII, scope(exit) ...;
От: Erop Россия  
Дата: 19.08.10 05:10
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Пока пробую выкрутиться без применения RAII ...



IMHO, в большинстве случаев можно забить на экономию одной ссылки.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: RAII, scope(exit) ...;
От: Centaur Россия  
Дата: 19.08.10 05:21
Оценка:
Здравствуйте, remark, Вы писали:

R>  static thread_local CTX* ctx;

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

void f(CTX& a, CTX& b)
{
    context usingA(a); // enter(a);
    context usingB(b); // enter(b);
    …;
} // exit(b); exit(b); // double-exit(b); leak(a);
Re[2]: RAII, scope(exit) ...;
От: Centaur Россия  
Дата: 19.08.10 05:25
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>В любом случае, попробуй так:

A>void do_something(context ctx, ...) // by value, context ctor should be implicit
A>{...


Без дополнительной информации я бы предположил, что копировать контекст нельзя — либо принципиально невозможно (поток ввода-вывода, объект со сложным поведением), либо слишком дорого (огромный массив данных).
Re: RAII, scope(exit) ...;
От: Centaur Россия  
Дата: 19.08.10 05:27
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Каждая переменная типа context содержит ссылку (указатель de facto) на CTX увеличивая тем самым размер стека функции.

CS>Можно ли как-нибудь избавитсься от этой context::ctx переменной?

Преждевременная оптимизация — sqrt(∀evil). Оптимизирующий компилятор, скорее всего, выоптимизирует эту ссылку.
Re[3]: RAII, scope(exit) ...;
От: CreatorCray  
Дата: 19.08.10 07:14
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>А вот интересно какова цена доступа к __declspec(thread) переменной?

CS>TLS как-нибудь через регистры процессора адресуется?

static __declspec (thread) Context* m_context;
...
m_context = NULL;


  mov       eax, DWORD PTR fs:[__tls_array]
  mov       eax, DWORD PTR [eax]
  mov       DWORD PTR [?m_context@@4PAVContext@@A+eax], 0
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Re[3]: RAII, scope(exit) ...;
От: remark Россия http://www.1024cores.net/
Дата: 19.08.10 07:34
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Здравствуйте, remark, Вы писали:


C>
R>>  static thread_local CTX* ctx;
C>

C>Так нельзя делать, потому что нельзя будет одним тредом войти рекурсивно в два разных контекста.

Вроде этого пока и не требовалось. А тех страшных вешей не будет — там специально ассёрты расставлены.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: RAII, scope(exit) ...;
От: remark Россия http://www.1024cores.net/
Дата: 19.08.10 07:41
Оценка: 38 (1)
Здравствуйте, c-smile, Вы писали:

CS>Как я понимаю thread_local __declspec(thread) либо __thread ?


Нет, почему, просто thread_local. Сам просил C++0x


CS>Если да то во всяком случае __declspec(thread) даже между разными windows не portable.

CS>User comment в http://msdn.microsoft.com/en-us/library/9w1sdazb(v=VS.80).aspx

Если этот код будет в дллке, то тогда надо вручную через TlsAlloc();


CS>А так в принципе как вариант оченно даже ...


CS>А вот интересно какова цена доступа к __declspec(thread) переменной?

CS>TLS как-нибудь через регистры процессора адресуется?

Там что-то типа двух косвенных обращений. Если использовать __declspec(thread), то они прямо будут встроены в твой код. Если же TlsAlloc(), то соотв. ещё будет вызов функции и ветвление.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: RAII, scope(exit) ...;
От: igna Россия  
Дата: 19.08.10 10:28
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Преждевременная оптимизация — sqrt(∀evil).


А почему корень квадратный, это что, дальнейшее развитие тезиса?
Re[4]: RAII, scope(exit) ...;
От: igna Россия  
Дата: 19.08.10 10:45
Оценка:
Здравствуйте, remark, Вы писали:

R>Нет, почему, просто thread_local. Сам просил C++0x


Разве он там не _Thread_local?
Re[5]: RAII, scope(exit) ...;
От: remark Россия http://www.1024cores.net/
Дата: 19.08.10 10:58
Оценка: +1
Здравствуйте, igna, Вы писали:

R>>Нет, почему, просто thread_local. Сам просил C++0x


I>Разве он там не _Thread_local?


_Thread_local в С1х


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: RAII, scope(exit) ...;
От: Кодт Россия  
Дата: 19.08.10 11:38
Оценка: :))) :)
Здравствуйте, igna, Вы писали:

C>>Преждевременная оптимизация — sqrt(∀evil).

I>А почему корень квадратный, это что, дальнейшее развитие тезиса?

А это и есть преждевременная оптимизация. Человек погорячился, конкретизировал степень, вызвал вопросы и нарекания.
Перекуём баги на фичи!
Re[3]: RAII, scope(exit) ...;
От: Centaur Россия  
Дата: 19.08.10 16:32
Оценка:
Здравствуйте, igna, Вы писали:

C>>Преждевременная оптимизация — sqrt(∀evil).


I>А почему корень квадратный, это что, дальнейшее развитие тезиса?


По умолчанию. Если над √ нет показателя степени — подразумевается, что он квадратный.
Re: RAII, scope(exit) ...;
От: SpaceConscience  
Дата: 19.08.10 17:16
Оценка: +1
Не понял, что это за экономия такая — четыре байта на функцию (ну даже восемь)?

Что, у тебя там такой космический уровень вложенности, что четыре байта уже делают погоду?
Собрался ставить минус? Да сам иди в жопу!

































































.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.