LINUX.ORG.RU
Ответ на: комментарий от lester

да - перед исключением не забудь flag сбросить обратно в false

lester ★★★★
()

да и по хорошему для этого пишется класс:

static bool alreadyCalled = false;
Checker( alreadyCalled );

который в конструкторе будет проверять callOnce на true и кидать исключение если надо, выставлять callOnce = true, а в деструкторе снова присваивать callOnce = false, тогда не надо будет руками нигде выставлять alreadyCalled

lester ★★★★
()
Ответ на: комментарий от stave

Нифига это не синглтон, хотя конечно можно делать по одному классу (имено классу, а не экземпляру) на 1 такую "нерекурсивную" функцию.

vnovouhov
()

Если нужно детектировать рекурсию в любом месте кода, то можно использовать __cyg_profile_func_enter а в нем сравнивать адреса. Если два последних адреса функций совпали, значит это рекурсивный вызов.

Должно сработать :-)

smh ★★★
()
Ответ на: комментарий от smh

Ну, конечно, не так просто сравнивать два последних адреса, а тот, что на вершине стека вызовов с текущим вызовом.

smh ★★★
()
Ответ на: комментарий от smh

> __cyg_profile_func_enter

это из цигвина что ли?

у жцц есть расширение, которое позовляет определить адрес вызова, но даже если и так -- функция может себя вызвать рекурсивно через цепочку, а не сразу.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от tailgunner

> Всё это не работает при вызове функции в разных нитях.

С учетом нитей -- вопрос топикстартера поставлен не до конца.

Я полагаю, что там не важно, рекурсивно или нет, важно что 2 раза. Там будет работать статик внутри функции? Мне кажется да.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> static лишний. Если бы был не лишний, то класс вообще можно было бы не писать.

с чего это? объясни на примере, если в моем убрать static - однозначно работать не будет

lester ★★★★
()
Ответ на: комментарий от tailgunner

> Всё это не работает при вызове функции в разных нитях.

слабо себе представляю рекурсию из одной нити в другую, точнее представляю, но не понимаю кому может понадобится такое писать

lester ★★★★
()
Ответ на: комментарий от www_linux_org_ru

> С учетом нитей -- вопрос топикстартера поставлен не до конца.

До конца. Рекурсивный вызов по определению происходит на одном стеке (== в рамках одной нити). Все предложенные способы в присуствии нескольких нитей дают false positive.

tailgunner ★★★★★
()
Ответ на: комментарий от lester

> с чего это? объясни на примере, если в моем убрать static - однозначно работать не будет

только щас до меня дошло, что static внутри функции неудобно и опасно

static в классе проблему решит, но не позволит запускать допустим 2 функции одновременно в разных нитях, автор топика ничего про это не сказал

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> только щас до меня дошло, что static внутри функции неудобно и опасно

почему?

> static в классе проблему решит


для каждой функции писать новый класс синглетон что-ли?

lester ★★★★
()
Ответ на: комментарий от tailgunner

> До конца. Рекурсивный вызов по определению происходит на одном стеке (== в рамках одной нити). Все предложенные способы в присуствии нескольких нитей дают false positive.

Формально подходя да. Но говоря "сделать нерекурсивной" топикстартер мог иметь ввиду "сделать нереентерабельной".

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от lester

> для каждой функции писать новый класс синглетон что-ли?

С помощью шаблонов -- элементарно.

>> только щас до меня дошло, что static внутри функции неудобно и опасно > почему?

Потому, что внутри функции может произойти исключение, а статичный хоть bool, хоть MyObject это не заметит.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> С помощью шаблонов -- элементарно.

продемонстрируйте плз

> Потому, что внутри функции может произойти исключение, а статичный хоть bool, хоть MyObject это не заметит.


деструктор то вызовется?

lester ★★★★
()
Ответ на: комментарий от lester

> деструктор то вызовется?

int function(int i) {
static bool b;
static MyObject x;
b=true;
g(i); // --> if( i%2 ) throw new Something();
b=false;
retrun i;
}

при вылете по иcключению деструктор MyObject не вызовется и b=false; тоже

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

что-то ваш пример совсем не похож на мой :)

lester ★★★★
()
Ответ на: комментарий от www_linux_org_ru

у меня всего две строки в начале функции, которые все и делают:

static bool alreadyCalled = false;
MyChecker checker( alreadyCalled );

lester ★★★★
()

threadsafe решение: можно сделать глобальный список в котором будут thread id тех нитей что функцию уже вызывали.

true_admin ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> чтобы показать, что и то, и другое не сработает

так никто и не говорил, что так сработает

lester ★★★★
()
Ответ на: комментарий от lester

Пример со статической переменной не будет работать даже в случае двух независимых вызовов функции в разных нитях. В первом потоке при первом вхождении в функцию статическая переменная установится в true, если в то же время эта же функция будет вызвана во втором потоке, то приведенный код ошибочно посчитает такой вызов как рекурсивный.

mannaz
()
Ответ на: комментарий от lester

> у меня всего две строки в начале функции, которые все и делают:

> static bool alreadyCalled = false;

> MyChecker checker( alreadyCalled );


А, так ты собрался передавать alreadyCalled по ссылке?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от mannaz

не спорю, но к счастью в большинстве случаев можно использовать и этот простой способ

lester ★★★★
()
Ответ на: комментарий от www_linux_org_ru

> А, так ты собрался передавать alreadyCalled по ссылке?

кстати, что мешает сделать так:

MyChecker::MyChecker( bool& flag )
{
mpPtr = &flag;
}

?

lester ★★★★
()
Ответ на: комментарий от www_linux_org_ru

> это из цигвина что ли?

Из gcc.

> у жцц есть расширение, которое позовляет определить адрес вызова, но даже если и так

__cyg_profile_func_enter - это оно и есть: http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Code-Gen-Options.html

> -- функция может себя вызвать рекурсивно через цепочку, а не сразу.

Топикстартер не говорил о таком случае, поэтому я предполагаю что он имел ввиду "простую" рекурсию...

smh ★★★
()
Ответ на: комментарий от lester

>> С помощью шаблонов -- элементарно. > продемонстрируйте плз

Оно хотя и элементарно, но

int i=non_reentrant<f,MyException,int,int>(1);

я уже написал, а чтобы писать

int i=non_reentrant<f,MyException>(1);

требуется почитать доки по бусту. И еще думаю потребуется boilerplate на разное к-во аргументов. Т.е. если кому вдруг очень интересно, напишу, а так лень.

Чтобы было non_recursive<f>(1) надо сделать thread-local вместо static, а в 4.4 его пока нет еще.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от smh

> __cyg_profile_func_enter - это оно и есть

Я так понял, оно у КАЖДОЙ функции будет вызваться. А я говорил про другое.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

Как топиккастер уточняю. Функция может вызваться через цепочку. Однако, моя реальная задача была проще, так как перевызванная через цепочку из нитей функция должна тоже выдавать исключение.

В прочем, лично я, когда поразмыслил над этим всем, решил ограничиться простыми административными мерами. :-) Но вы можете продолжать...

yz
() автор топика
Ответ на: комментарий от www_linux_org_ru

А, да, забыл уточнить! Надо чтобы работало, будучи скомпилированным под Win, Linux, Solaris и AIX ихними родными компиляторами.

yz
() автор топика
Ответ на: комментарий от lester

> зачем тут шаблоны? можно написать класс, где в конструкторе тот же набор параметров

шаблоны тут в предположении, что таких нереентерабельных функций много, и вместо того, чтобы делать руками...

хотя может удобнее будет макрос с переменным числом аргументов.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от yz

> А, да, забыл уточнить! Надо чтобы работало, будучи скомпилированным под Win, Linux, Solaris и AIX ихними родными компиляторами.

И? static и деструкторы они все понимают надеюсь?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от xydo

Штука, которую мы здесь пытались реализовать следует назвать thread-local mutex. :)

naryl ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.