информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Атака на InternetЗа кого нас держат?
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Блокировка российских аккаунтов... 
 Отзыв сертификатов ЦБ РФ, ПСБ,... 
 Памятка мирным людям во время информационной... 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
[C++] а точно один? 17.09.08 01:50  Число просмотров: 2141
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
> Сегодня второй раз за три месяца заметил, что в объекте
> пропадают мемберы - был map заполнен, а на следующей строке
> - он уже пуст. Был мембер-указатель валидным, не трогали
> его, а он уже непонятно куда указывает.
> Симптомы проявлялись когда:
> 3. Оба синглетона были еще и потоками: void Start() { new
> boost::thread( ref(*this)); } Кстати, черти проявляются
> именно после вызова Start(). Но, не факт что это причина.
> И это не проблема "двойного синглетона" - объект
> действительно один и тот же.

Если воткнуть отладочную печать/брекпойнт в конструктор S и конструктор класса мембера, лишние заходы туда не проявляются?
<programming>
[C++] По реализации синглетона вопрос 17.09.08 00:37  
Автор: PS <PS> Статус: Elderman
Отредактировано 17.09.08 01:24  Количество правок: 1
<"чистая" ссылка>
Даже не вопрос...
Есть такая реализация:
class S
{
  public:
      static S& Instance()
      {
        static S inst;
        return inst;
      }
  private:
   ....
};

---

Так вот, реализация вполне валидная, красивая, короткая - всем хороша.
Только вот иногда не работает.
Сегодня второй раз за три месяца заметил, что в объекте пропадают мемберы - был map заполнен, а на следующей строке - он уже пуст. Был мембер-указатель валидным, не трогали его, а он уже непонятно куда указывает.
Симптомы проявлялись когда:
1.Синглетон объявлен и реализован в exe. А тип какого нибудь мембера (он даже может быть указателем) объявлен и реализован в dll.
2. Оба exe (оба раза) это были сервисы.
3. Оба синглетона были еще и потоками: void Start() { new boost::thread( ref(*this)); } Кстати, черти проявляются именно после вызова Start(). Но, не факт что это причина.

На настройки проекта не грешить - выравнивания, (/MD) и пр. - все корректно и совпадает.
И это не проблема "двойного синглетона" - объект действительно один и тот же.
Порушенный стек, куча - отпадают. Код полностью safe (если, конечно, stl и boost можно считать safe). к тому же при поиске причины - код был сведен к минимуму: осталась только иницализация сервиса, инициализация синглетона, и Start.

Лечится просто: либо переносишь этот класс в dll, либо отказываешся от его синлетонности и делаешь объект, скажем, мембером основного класса приложения.

Чешу репу.
Кто нибудь с таким сталкивался?

P.S.
Чую, что дело бесовское, а обосновать не могу.
ПИП! ПИП! ПИП! ПИП! 17.09.08 18:53  
Автор: PS <PS> Статус: Elderman
<"чистая" ссылка>
тут много много мата...
тут очень много мата...
тут столько мата, что форумная чекилка сломалась, у боцманов завяли уши, а воробьи упали мертвыми на землю.
ПИП! ПИП! ПИП! ПИП!

Весь день гонялся за багой: сначала избавился от потоков. Стабильно не работает.
Потом избавился от остальных объектов. Стабильно не работает.
Избавился от сервиса, и сделал консоль. Стабильно не работает.
В синглетоне оставил только один метод. Стабильно не работает.

Код девственно чист, есть только синглетон который выводит строчку в файл. Имя файла задается ф-ией Init(). Потоков нет, буста нет, консольное приложение - стабильно не работает. Имя файла между Init() и Write() исчезает, видимо в параллельное пространство.

ПИП!ПИП!ПИП!ПИП!

Заменил /O2 на /Od
Заработало!

ПИП!ПИП!ПИП!ПИП!

Сцука оптимизатор.
А если локальную статическую переменную объявить еще и... 18.09.08 03:42  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
А если локальную статическую переменную объявить еще и волатильной?
Это точно... Вопрос старый и весьма избитый. Наиболее... 17.09.08 07:35  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
> Даже не вопрос...
Это точно... Вопрос старый и весьма избитый. Наиболее содержательный ответ можешь най ти в очётах Мейра и Александреску - "Double-Checked Locking, Threads,Compiler Optimizations,and More Scott Meyers, Ph.D. Software Development Consultant (Based on Work with Andrei Alexandrescu.)"
Неплохое ридинг такогоже уровня - "Double-Checked Locking An Optimization Pattern for Efficiently Initializing and Accessing Thread-safe Objects Douglas C. Schmidt, Tim Harrison".

Всё остальное (статьи)- глупости и весьма пустые вариации на эту тему, ИМХО. В статьях, что выше ты найдёшь такой вывод - в VS 2005 - легко сделать (см. Мейра), поскольку volatile реализовано на memory barrier (в отличие от предыдущих версий копиллеров).
Ты гарантируешь первый вызов Instance из однопоточного [upd] 17.09.08 04:16  
Автор: amirul <Serge> Статус: The Elderman
Отредактировано 17.09.08 04:19  Количество правок: 1
<"чистая" ссылка>
> Чешу репу.
> Кто нибудь с таким сталкивался?

Ты гарантируешь первый вызов Instance из однопоточного окружения?

> P.S.
> Чую, что дело бесовское, а обосновать не могу.

-------------
Кроме того, по хорошему стоило бы захватывать какую нибудь критическую секцию в самом начале S::Instance
Да, гаранитую 17.09.08 12:15  
Автор: PS <PS> Статус: Elderman
<"чистая" ссылка>
Да, первый вызов Instance() идет только из одного потока.
Код примерно следующий.

S1::Instance().Init()
S2::Instance().Init()
S3::Instance().Init()
...
S1::Instance().Start()

Первые вызовы идут в одном потоке.
Остальные потоки появляются только после инициализации всех синглетонов.

void тут высказывается про ровные места. Если бы они были бы ровными - поста бы не появилось.

У меня появилось другое предположение. Давно заметил, что boost::thread ведет себя не корректно в "кислотной среде".
Есть у меня код, доставшийся по наследству: он полностью unsafe, буфера, которые могут переполнится, указатели пущенные в свободное плавание, доступ к переменным из потоков не залоченые, и все остальные прелести.
Так вот в этом коде new boost::thread вываливается с эксепшеном.
Так что его можно использовать как детектор "что-то где-то плохо".

Так вот, не создал ли я где то в своем safe коде, какой нить косяк... буду разбираться. Если косяк действительно есть, то удалю этот пост. Если нарвусь на что-то более интересное - напишу.
Да, гаранитую ? 17.09.08 18:09  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
> void тут высказывается про ровные места. Если бы они были
> бы ровными - поста бы не появилось.

In the simplest case you might try this. No?

////////////////////////////////////////////////////////////////////
// My_class.cpp

class My_class
{
public:
	static My_class& unsafe_instance()
	{
		static My_class inst;
		return inst;
	}
	bool initialize(void)
	{
		bool rc = false;
		// TO DO
		return rc;
	}
	void deinitialize(void)
	{
		// TO DO before dtor()
	}
private:
	My_class()
	{
	}
	~My_class()
	{
	}
	My_class& operator =(const My_class&);
};


static struct init_my_class
{
	init_my_class() : m_instance(My_class::unsafe_instance())
	{
		m_initialized = m_instance.initialize();
	}
	~init_my_class()
	{
		 m_instance.deinitialize();
	}
	bool m_initialized;
	My_class& m_instance;
	init_my_class& operator=(const init_my_class&);
} _init_my_class_;


void initialize_my_classes(void)
{
	if (false ==init_my_classm_initialized)
	{
		throw std::exception("an error at init_my_class startup");
	}
/* TO DO
	else if ()
	{
		throw std::exception("an error at ....");
	}
*/
	else
	{
	}
}

////////////////////////////////////////////////////////////////////
// main.cpp

int _tmain(int argc, _TCHAR* argv[])
{
	try
	{
		// there is only a place where you initialize/check your statics
		initialize_my_classes();
	}
	catch(std::exception& e)
	{
		printf("Failed to initialize my staff (%s)", e.what());
		return 1;
	}
	catch(...)
	{
		printf("Failed to initialize my staff (unhandled exception at startup)");
		return 1;
	}

	return 0;
}

---
Если бы он мог гарантировать - то он не писал бы про... 17.09.08 07:45  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
> > Чешу репу.
> > Кто нибудь с таким сталкивался?
>
> Ты гарантируешь первый вызов Instance из однопоточного
> окружения?
Если бы он мог гарантировать - то он не писал бы про "чудеса" на ровном месте.
Я наверное чего то недопонял 17.09.08 11:17  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> > Ты гарантируешь первый вызов Instance из однопоточного
> > окружения?
> Если бы он мог гарантировать - то он не писал бы про
> "чудеса" на ровном месте.

А что мешает вызвать S::Instance из первого потока, чтобы проинициализировать статическую переменную и уж потом создавать новые? Кроме того, однопоточность функции можно гарантировать простенькой критической секцией (лучше завернутой в объект - чтоб не следить за освобождением)

Или проблема в чем то еще?
If he does exactly this way, there should be no problem. 17.09.08 17:36  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
[C++] а точно один? 17.09.08 01:50  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
> Сегодня второй раз за три месяца заметил, что в объекте
> пропадают мемберы - был map заполнен, а на следующей строке
> - он уже пуст. Был мембер-указатель валидным, не трогали
> его, а он уже непонятно куда указывает.
> Симптомы проявлялись когда:
> 3. Оба синглетона были еще и потоками: void Start() { new
> boost::thread( ref(*this)); } Кстати, черти проявляются
> именно после вызова Start(). Но, не факт что это причина.
> И это не проблема "двойного синглетона" - объект
> действительно один и тот же.

Если воткнуть отладочную печать/брекпойнт в конструктор S и конструктор класса мембера, лишние заходы туда не проявляются?
Точно. Только узнавал подругому: сделал S* Instance(), 17.09.08 01:59  
Автор: PS <PS> Статус: Elderman
Отредактировано 17.09.08 02:16  Количество правок: 3
<"чистая" ссылка>
Точно. Только узнавал подругому: сделал S* Instance(),
а перд вызовами вывожу в лог указатель.

void S::operator()()
{
  S* tmp = S::Instance();
  Log::Instance()->Trace( (long)tmp );
  vector<string> t1 = S::Instance()->t; // тут все ок.

   tmp = S::Instance();
  Log::Instance()->Trace( (long)tmp );
  vector<string> t2 = S::Instance()->t; // тут все ок.

  while( true )
  {
     tmp = S::Instance();
     Log::Instance()->Trace( (long)tmp );
     vector<string> t3 = S::Instance()->t; // а тут бред!
  }
}

---

первый, второй и третий лог - выдает одно и то же.

Кстати, здесь видно что я из потока обращаюсь к мемберам на прямую. Это валидно, т.к. запись в них происходит только в Init(); которая вызывается до Start();
Больше никто не трогает эти мемберы (ни на запись, ни на чтение).


> Если воткнуть отладочную печать/брекпойнт в конструктор S и
> конструктор класса мембера, лишние заходы туда не
> проявляются?
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2022 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach