Storing thread local using Thread Local Storage (TLS)

Have you ever needed to store data locally to a thread ? For example, let’s say that you want to implement a GetLastErrorMsg() function. This function would complement the standard GetLastError() one by providing a string description of the last error.

How would you implement it ? You need to store the error description on a per thread basis. Will you use a map whose key would be the thread ID and data the error message ? Since you don’t know when threads terminate, when will you delete entries of the map ? What happens if a thread terminates and a new one starts with the same thread ID ? This is definitely not a good approach !

A nicer and easier solution is to use the __declspec( thread ) directive (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_pluslang_the_thread_attribute.asp).

This directive allows you to specify that a global or member variable is local to a thread. Each time you will use the variable, it will the one specific to the thread, and will be deallocated once it is terminated.

The following code illustrates the use of this directive for the implementation of the GetLastErrorMsg() function.

The thread local storage can be used dynamically too, using the TlsAlloc(), LocalAlloc(), TlsSetValue() and TlsGetValue() functions. This is useful when working with DLL to store Data when threads attach to and detach from the DLL. See the MSDN article about this : “Using Thread Local Storage in a Dynamic-Link Library” (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/using_thread_local_storage_in_a_dynamic_link_library.asp)

#include "stdafx.h"
#include "myError.h"
using namespace std;

__declspec( thread ) char g_szMsg[256] = "";

 const char* GetMyLastErrorMsg() { return g_szMsg; }

void SetMyLastErrorMsg( const char* szMsg) {
    strcpy( g_szMsg, szMsg); 
}

UINT MyThread( LPVOID pParam )
{
    int iDelay = (int)pParam;
    char szMsg[ 256 ];
    sprintf( szMsg, "Thread %d Message %d", GetCurrentThreadId(), iDelay );
    SetMyLastErrorMsg( szMsg );
    cout << "Set " << szMsg << endl;
    Sleep( iDelay );
    cout << "Get " << GetMyLastErrorMsg() << endl;
    return 0;
} // UINT MyThread

int main(int argc, char* argv[])
{
    CWinThread* pThread = NULL;
    for ( int i = 1; i <= 10; i++ )
    {
        pThread = AfxBeginThread( MyThread, (LPVOID)(i * 1000) );
    }

    WaitForSingleObject( pThread->m_hThread, INFINITE );
    return 0;
}

C++ IMAP client component

I needed to replace the Easymail IMAP client component that my company uses because it doesn’t support imbricated forwarded attachment ( an attachment which is a mail containing an attachment which is mail containing an attachment which is a mail, …)

I found different IMAP clients :

  1. The one which looked better a first was the n-software Ip*Works solution (www.nsoftware.com). This IMAP component is really well designed and support imbricated attachments. However, it appeared that it is not thread safe. Calling a method of the IMAP class from a thread different from the one in which the class was instanciated causes strange behaviour ( slow answer from the server). The n-software support confirmed it’s a known issue, and that it cannot be fixed. What a pity 🙁
  2. I tried the Chilkat IMAP component (www.chilkatsoft.com/). It was presented as thread safe, and stress tested in ASP farms. Although the component is not really well designed, I tried it. But it appeared that it didn’t work with all the IMAP servers I tried (especially the Vircom Modus one), and in some cases it throws exception (access violation)  when the documentation said it shouldn’t. Moreover, in the very simple demo application I wrote. I had memory leaks even when only doing a login logout… I may have been unlucky with my tests, but I will avoid this component.
  3. Finally, I tested a IMAP client from Hunny Soft (http://www.hunnysoft.com/mailpp/index.htm). First, I noticed that it was possible to purchase the source code of this component. And finally, this is the BIG WINNER ! It really is well designed, easy to use, efficient. It looks like it can be used in a multi thread context without problems. That’s the one I will recommend !

Basics for catching a windows message manually

In the following sample, we catch the WM_RBUTTONDOWN message. This would work for any windows message :

  1. In the AFX_MSG section of your .h file, add the declaration of your message handler function :
     //{{AFX_MSG(CMyCtrl)
    // NOTE – the ClassWizard will add and remove member functions here.
    afx_msg LRESULT OnRBtnDown(WPARAM wParam, LPARAM lParam); // handler function
    //}}AFX_MSG
  2. Add the body of your function in your .cpp file :
    LRESULT CMyCtrl::OnRBtnDown(WPARAM wParam, LPARAM lParam)
    {
    AfxMessageBox(“WM_RBUTTONDOWN caught”);
    return 0;
    } // LRESULT CMyCtrl::OnRBtnDown
  3. In the message map of your .cpp file, add the following :
    BEGIN_MESSAGE_MAP(CMyCtrl, CWnd)
    //{{AFX_MSG_MAP(CFilteredListCtrl)
    // NOTE – the ClassWizard will add and remove mapping macros here.
    ON_MESSAGE(WM_RBUTTONDOWN, OnRBtnDown)
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()

However, some shortcuts allows you to take care of standard messages. For example, the WM_RBUTTONDOWN message can be caught with :

  1. //{{AFX_MSG(CMyCtrl)
    // NOTE – the ClassWizard will add and remove member functions here.
    afx_msg void OnRButtonDown( UINT nFlags, CPoint point );
    //}}AFX_MSG
  2. void CMyCtrl::OnRButtonDown( UINT nFlags, CPoint point )
    {
    CWnd::OnRButtonDown( nFlags, point );
    } // void CMyCtrl::OnRButtonDown
  3. BEGIN_MESSAGE_MAP(CMyCtrl, CWnd)
    //{{AFX_MSG_MAP(CMyCtrl)
    // NOTE – the ClassWizard will add and remove mapping macros here.
    ON_WM_RBUTTONDOWN()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()

You can apply the same approach to many WM_XXX messages.

Troubles displaying a popup menu dynamically

Damian Powell
Oct 18 1999, 2:00 am   show options
Newsgroups: microsoft.public.vc.mfc
From: Damian Powell <damian_pow@my-deja.com> – Find messages by this author
Date: 1999/10/18
Subject: CMenu::TrackPopupMenu – strange behaviour.
Reply to Author | Forward | Print | Individual Message | Show original | Report Abuse

Hello everyone,

I’m using the following code to display a popup-menu from a CDialog
derrived object but it doesn’t seem to work correctly.

When the menu is displayed, it appears as a thin-ish vertical line with
no text. However, the highlight does move as I move the mouse down the
menu and the correct menu items are selected from the various positions.

Can anyone tell me what I am doing wrong?

void CRs232ClientDlg::OnRButtonDown(UINT nFlags, CPoint point)
{
CDialog::OnRButtonDown(nFlags, point);
ClientToScreen(&point);
CMenu menu;
menu.LoadMenu(IDR_MENU1);
menu.TrackPopupMenu (
TPM_LEFTALIGN|TPM_LEFTBUTTON,
point.x,
point.y,
this
);

 

}

Thanks in advance,
Damian.
Sent via Deja.com http://www.deja.com/
Before you buy.

Douglas Peterson
Oct 18 1999, 2:00 am   show options
Newsgroups: microsoft.public.vc.mfc
From: Douglas Peterson <douglas.peter@nospam.telex.com> – Find messages by this author
Date: 1999/10/18
Subject: Re: CMenu::TrackPopupMenu – strange behaviour.
Reply to Author | Forward | Print | Individual Message | Show original | Report Abuse

There may be an “appropriate” solution, I don’t know, but this works:

Create your menu (IDR_MENU1) with a single popup menu item (sub-menu)
and put the “real” popup as items in this sub.  Then get the menu like
this:

menu.LoadMenu(IDR_MENU1);
CMenu* pPopup = menu.GetSubMenu(0);
pPopup->TrackPopupMenu(…)

 

– Show quoted text –

 

 

Bob Moore
Oct 18 1999, 2:00 am   show options
Newsgroups: microsoft.public.vc.mfc
From: Bob Moore <b@mvps.org> – Find messages by this author
Date: 1999/10/18
Subject: Re: CMenu::TrackPopupMenu – strange behaviour.
Reply to Author | Forward | Print | Individual Message | Show original | Report Abuse

 

On Mon, 18 Oct 1999 15:42:39 GMT, Damian Powell wrote:
>When the menu is displayed, it appears as a thin-ish vertical line with
>no text. However, the highlight does move as I move the mouse down the
>menu and the correct menu items are selected from the various positions.

You’ve loaded a bar menu rather than a popup.