//Константная строкаstatic const CString get_String()
{
static const CString str = MakeString(); //где MakeString довольно ресурсоемкая функция,
// которую не хочется вызывать каждый разreturn str;
}
//несколько Thread-ов, которые этой строкой пользуются:void Thread()
{
for (;;)
{
log.AddMessage (get_String());
}
}
Из-за того, что const CString на самом деле не константый объект (у него модифицируется счетчик ссылок), все падает.
Как быть?
На ум приходит, только одно решение, при возврате строки говорит CString-у, чтобы он делал копию, а не увеличивал счетчик.
Но это тоже не выход, т.к. строка может быть до нескольких килобайтов, а функция дергается довольно часто.
Более общий вопрос, как лучше писать код, которые использует константные объекты из нескольких thread-ов?
Получается, что для таких объектов вообще нельзя пользоваться ссылками, а можно только передавать объекты по значению.
Здравствуйте DarkGray, Вы писали:
DG>Столкнулся на днях с такой проблемой:
DG>Есть следующий код (немного упрощенный): DG>
DG>//Константная строка
DG>static const CString get_String()
DG>{
DG> static const CString str = MakeString(); //где MakeString довольно ресурсоемкая функция,
DG> // которую не хочется вызывать каждый раз
DG> return str;
DG>}
DG>//несколько Thread-ов, которые этой строкой пользуются:
DG>void Thread()
DG>{
DG> for (;;)
DG> {
DG> log.AddMessage (get_String());
DG> }
DG>}
DG>
DG>Из-за того, что const CString на самом деле не константый объект (у него модифицируется счетчик ссылок), все падает.
Так смотря как он модифицируется...
DG>Как быть?
Это MFCшный CString или нет? Конкретнее, как у него подсчет ссылок реализован?
DG>На ум приходит, только одно решение, при возврате строки говорит CString-у, чтобы он делал копию, а не увеличивал счетчик.
Или, например, синхронизировать доступ к CString, или вообще возвращать из get_String возвращать const char *.
DG>Но это тоже не выход, т.к. строка может быть до нескольких килобайтов, а функция дергается довольно часто.
DG>Более общий вопрос, как лучше писать код, которые использует константные объекты из нескольких thread-ов? DG>Получается, что для таких объектов вообще нельзя пользоваться ссылками, а можно только передавать объекты по значению.
Почему? Для настоящих константных объектов?
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте DarkGray, Вы писали:
DG>static const CString get_String() DG>{ DG> static const CString str = MakeString(); //где MakeString довольно ресурсоемкая функция, DG> // которую не хочется вызывать каждый раз DG> return str; DG>}
DG>//несколько Thread-ов, которые этой строкой пользуются: DG>void Thread() DG>{ DG> for (;) DG> { DG> log.AddMessage (get_String()); DG> } DG>} DG>[/ccode]
А не нужно ли синхронизировать static переменную внутри функции? Ее всетаки ковыряют нескоолько потоков, хоть она и const но если RefCount меняется то может что нехорошее и происходит.
А может это MFC'шные глюки она потоко-капризная не зря же в MSDN такие предложения встречаются:
... If you have a multithreaded application that creates a thread in a way other than using a CWinThread object, you cannot access other MFC objects from that thread.
... MFC objects are not thread-safe at the object level, only at the class level
... As a general rule, a thread can access only MFC objects that it created
Здравствуйте Silver_s, Вы писали:
SS>А не нужно ли синхронизировать static переменную внутри функции? Ее всетаки ковыряют нескоолько потоков, хоть она и const но если RefCount меняется то может что нехорошее и происходит.
Ставить Lock на getString() не помогает, т.к. если увеличение счетчика происходит именно в get_String(), то уменьшение счетчика непонятно где.
Re: ref_count strings & threads
От:
Аноним
Дата:
15.05.02 12:43
Оценка:
Здравствуйте DarkGray, Вы писали:
DG>Столкнулся на днях с такой проблемой:
DG>Есть следующий код (немного упрощенный): DG>
DG>//Константная строка
DG>static const CString get_String()
DG>{
DG> static const CString str = MakeString(); //где MakeString довольно ресурсоемкая функция,
DG> // которую не хочется вызывать каждый раз
DG> return str;
DG>}
DG>//несколько Thread-ов, которые этой строкой пользуются:
DG>void Thread()
DG>{
DG> for (;;)
DG> {
DG> log.AddMessage (get_String());
DG> }
DG>}
DG>
DG>Из-за того, что const CString на самом деле не константый объект (у него модифицируется счетчик ссылок), все падает.
DG>Как быть?
DG>На ум приходит, только одно решение, при возврате строки говорит CString-у, чтобы он делал копию, а не увеличивал счетчик. DG>Но это тоже не выход, т.к. строка может быть до нескольких килобайтов, а функция дергается довольно часто.
DG>Более общий вопрос, как лучше писать код, которые использует константные объекты из нескольких thread-ов? DG>Получается, что для таких объектов вообще нельзя пользоваться ссылками, а можно только передавать объекты по значению.
А зачем возвращать строку по значению? Почему бы не вернуть ссылку на нее?
Здравствуйте Sergey, Вы писали:
DG>>Из-за того, что const CString на самом деле не константый объект (у него модифицируется счетчик ссылок), все падает.
S>Так смотря как он модифицируется...
+1 в конструкторе/-1 в деструкторе, простым инкрементом
DG>>Как быть?
S>Это MFCшный CString или нет? Конкретнее, как у него подсчет ссылок реализован?
в данном случае WTL::CString,
InterlockedIncrement\InterlockedDecrement
DG>>На ум приходит, только одно решение, при возврате строки говорит CString-у, чтобы он делал копию, а не увеличивал счетчик.
S>Или, например, синхронизировать доступ к CString, или вообще возвращать из get_String возвращать const char *.
Синхроyизировать доступ не получается, т.к. уменьшение счетчика происходит не понятно где...
DG>>Более общий вопрос, как лучше писать код, которые использует константные объекты из нескольких thread-ов? DG>>Получается, что для таких объектов вообще нельзя пользоваться ссылками, а можно только передавать объекты по значению.
S>Почему? Для настоящих константных объектов?
А что это такое?
В данном коде, Const — настоящий константный объект или не настоящий?
Здравствуйте DarkGray, Вы писали:
DG>Здравствуйте Sergey, Вы писали:
DG>>>Из-за того, что const CString на самом деле не константый объект (у него модифицируется счетчик ссылок), все падает.
S>>Так смотря как он модифицируется...
DG>+1 в конструкторе/-1 в деструкторе, простым инкрементом
Где там простой инкремент/декремент? Какая версия WTL?
S>>Это MFCшный CString или нет? Конкретнее, как у него подсчет ссылок реализован? DG>в данном случае WTL::CString, DG>InterlockedIncrement\InterlockedDecrement
Тогда с подсчетом ссылок проблем быть не должно, скорее всего либо используешь неконстантные касты, либо где-то в реализации CString есть другая ошибка.
DG>>>На ум приходит, только одно решение, при возврате строки говорит CString-у, чтобы он делал копию, а не увеличивал счетчик.
S>>Или, например, синхронизировать доступ к CString, или вообще возвращать из get_String возвращать const char *.
DG>Синхроyизировать доступ не получается, т.к. уменьшение счетчика происходит не понятно где...
Типа так:
void Thread()
{
for (;)
{
EnterCriticalSection(..);
log.AddMessage (get_String());
LeaveCriticalSection(..);
}
}
DG>>>Более общий вопрос, как лучше писать код, которые использует константные объекты из нескольких thread-ов? DG>>>Получается, что для таких объектов вообще нельзя пользоваться ссылками, а можно только передавать объекты по значению.
S>>Почему? Для настоящих константных объектов?
DG>А что это такое?
DG>В данном коде, Const — настоящий константный объект или не настоящий? DG>
Здравствуйте DarkGray, Вы писали:
DG>Здравствуйте Sergey, Вы писали:
S>>А это вообще не должно компилироваться, насколько я понимаю. DG>А ты пробовал компилировать? '*p', конечно, должно стоять в скобках
Со скобками, естественно, скомпилируется. Потому что то, куда показывает p, к объекту никаким боком не относится.
DG>
Здравствуйте DarkGray, Вы писали:
DG>Здравствуйте Sergey, Вы писали:
S>>Типа так: S>>void Thread() S>>{
S>> for (;) S>> { S>> EnterCriticalSection(..); S>> log.AddMessage (get_String()); S>> LeaveCriticalSection(..); S>> } S>>}
DG>Так деструктор для CString'а все равно может вызваться вне блокировки.
DG>
DG>CLog
DG>{
DG> CString s;
DG> CComAutoCriticalSection cs;
DG> AddMessage (const CString&s)
DG> {
DG> CAutoLock lock(cs);
DG> this->s = s;
DG> }
DG> CString get_Message ()
DG> {
DG> CAutoLock lock(cs);
DG> return s;
DG> }
DG>};
DG>void Thread ()
DG>{
DG> for (;;)
DG> {
DG> EnterCriticalSection(..);
DG> log.AddMessage (get_String());
DG> LeaveCriticalSection(..);
DG> }
DG>}
DG>void AnotherThread()
DG>{
DG> for (;;)
DG> {
DG> CString s = log.get_Message();
DG> //здесь вызовется деструктор все того же "static стринга", но он будет уже без всякого локинга
DG> }
DG>}
DG>
А что мешает написать так?
void AnotherThread()
{
for (;;)
{
EnterCriticalSection(..);
CString s = log.get_Message();
LeaveCriticalSection(..);
}
}
А вообще, IMHO, проблемы там с чем угодно, только не с подсчетом ссылок. Например, если один поток начинает модифицировать CString, который вернул get_Message, а другой — менять CLog::s.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
void AnotherThread()
{
for (;;)
{
EnterCriticalSection(..);
{ CString s = log.get_Message(); }
LeaveCriticalSection(..);
}
}
S>А вообще, IMHO, проблемы там с чем угодно, только не с подсчетом ссылок. Например, если один поток начинает модифицировать CString, который вернул get_Message, а другой — менять CLog::s.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте DarkGray, Вы писали:
DG>Здравствуйте ppp, Вы писали:
ppp>>Знаешь, я не поленился и набил у себя аналогичный код — у меня все нормально. Так что ищи ошибку в другом месте.
DG>Так у меня он тоже не каждый раз падает, а один раз на двадцать запусков...
так не считается... Либо всегда падает в процессе работы, либо у тебя где-то в другом месте крашится память
Здравствуйте DarkGray, Вы писали:
DG>Здравствуйте ppp, Вы писали:
ppp>>так не считается... Либо всегда падает в процессе работы, либо у тебя где-то в другом месте крашится память
DG>Или иногда одновременно что-то правят.
DG>Если твой код чуть-чуть подправить, то он начинает падать DG>