понедельник, 26 января 2009 г.

LockingPtr and volatile - Multithreaded Programmer's Best Friends

There is a great article of Andrei Alexandrescu "volatile - Multithreaded Programmer's Best Friend" (russian version).

Here it is! Our Smart Friend:
template <typename T, typename Mutex = CSyncObject>
class LockingPtr
{
public:
// Constructors/destructors
LockingPtr(volatile T& obj, Mutex& mtx)
: pObj_(const_cast<T*>(&obj)),
pMtx_(&mtx)
{
mtx.Lock();
}
~LockingPtr()
{
pMtx_->Unlock();
}

// Pointer behavior
T& operator* () { return *pObj_; }
T* operator->() { return pObj_; }

private:
T* pObj_;
Mutex* pMtx_;
LockingPtr(const LockingPtr&);
LockingPtr& operator=(const LockingPtr&);
};


"In spite of its simplicity, LockingPtr is a very useful aid in writing correct multithreaded code. You should define objects that are shared between threads as volatile and never use const_cast with them — always use LockingPtr automatic objects."

Here is an example:
bRes = Write(strParams);
if (bRes)
{
tmTimer.Begin();
stWait( (bRes = sName[LD_Printer] == strReceived) ||
(bTimeout = tmTimer.isTimeout(_Settings.dwTimeout) == TRUE ) );

{
LockingPtr<TStringList> lpDocCVS(_DocCVS, _csLock);
if (!lpDocCVS->empty())
lpDocCVS->pop_front();
}

if (!bRes && bTimeout)
{
_Log.TWriteLn("!! TIMEOUT !!");
}
}

33 Коровы по почте !!!


Получил на днях вот такое вот письмо! Реклама, но порадовала. Странно что письмо пришло на адрес, где я уже не живу почти 4 года. Все чудесатее и чудесатее (ц)Алиса в Зазеркалье

пятница, 23 января 2009 г.

Мелочь, а приятно :)

Возвращались вчера от заказчика и заехали в БургерКинг перекусить. Расплачиваясь, показал своему немецкому коллеге украинские 10 гривен и 2 гривны. Он поинтересовался сколько это в евро. Переварив ответ, выдал фразу:
- Мне кажется, что бумажные деньги удобнее чем мелочь!

То что есть еще и копейки, я ему уже не рассказывал :)

вторник, 20 января 2009 г.

Мама мыла раму...

После попытки написать что-то осмысленное в своем блоге, понял, что с письменной речью и грамматикой у меня нелады :(

Грабли::TerminateThread and memory allocating/deallocating deadlock

Do you remember this piece of code? Looks it similar to you?

void operator delete(
void *pUserData
)
{
_CrtMemBlockHeader * pHead;

RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));

if (pUserData == NULL)
return;

_mlock(_HEAP_LOCK); /* block other threads */ <--- Here it hangs !!!
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);

/* verify block type*/
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));

_free_dbg( pUserData, pHead->nBlockUse );

__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY

return;
}


If you'll kill a thread in the wrong moment after _mlock(_HEAP_LOCK) but before _munlock(_HEAP_LOCK) the next call of a function that uses _HEAP_LOCK will hang!

I've spent a lot of time to find this out...

Some more info:
Improving Performance with Thread-Private Heaps by Kevin Manley

Jochen Kalmbach writes in his blog about this problem also:
Why you should never call Suspend/TerminateThread (Part I)
Why you should never call Suspend/TerminateThread (Part II)