tags:

views:

359

answers:

1

I'm using a map as a thread specific cache to keep track of failed LDAP searches. I dynamically allocate the map and store the pointer using pthread_setspecific. When checking the cache or incrementing the failure count I use pthred_getspecific in order to retrieve the void* pointer and static_cast the pointer back to my map type. Calls to the map using the [] operator don't appear to affect the state of the map and calls to map->size() always return 0. It feels like I'm probably incorrectly using pthread_getspecific but from the examples I've looked at my code looks right.

Code:

typedef std::map<std::string, int>  FailedSearchCacheMap;

/**
 * Create the keyserver failed search cache key. Only called 
 * internally and may only be called once per thread.
 */
static void
sCreateKeyserverFailedSearchCache(void)
{
    // Create the key used in refrencing the cache.  
    // sFreeKeyserverFailedSearch called against the pointer when the thread exits
    pthread_key_create(&sFailedSearchCacheKey, sFreeFailedSearchCache);
}

/**
 * Get the keyserver failed search cache (also create one if it doesn't exist)
 */
static FailedSearchCacheMap *
sGetKeyserverFailedSearch(void)
{
    // Initializes the failed search cache key.  
    // pthread_once guarantees that the create key routine is only called once
    static pthread_once_t sKeyserverFailedSearchOnce = PTHREAD_ONCE_INIT;
    pthread_once(&sKeyserverFailedSearchOnce, sCreateKeyserverFailedSearchCache);

    FailedSearchCacheMap* cache = static_cast<FailedSearchCacheMap *>(pthread_getspecific(sFailedSearchCacheKey));
    if (IsNull(cache))
    {
     cache = new FailedSearchCacheMap();
     pthread_setspecific(sFailedSearchCacheKey, cache);
    }

    return cache;
}


Test Code:

FailedSearchCacheMap* map_ptr1 = sGetKeyserverFailedSearch();
FailedSearchCacheMap* map_ptr2 = sGetKeyserverFailedSearch();

std::string ks("hostname");
FailedSearchCacheMap map1 = *map_ptr1;
FailedSearchCacheMap map2 = *map_ptr2;

int numFailedSearches = map1[ks] + 1;
map1[ks] = numFailedSearches;

std::cout << "numFailedSearches: "  << numFailedSearches << std::endl;

std::cout << "map_ptr1 address: "   << map_ptr1 << std::endl;
std::cout << "map_ptr2 address: "   << map_ptr2 << std::endl;

std::cout << "map_ptr1->size(): "   << map_ptr1->size() << std::endl;
std::cout << "map_ptr2->size(): "   << map_ptr2->size() << std::endl;

std::cout << "map1.size(): "     << map1.size() << std::endl;
std::cout << "map2.size(): "     << map2.size() << std::endl;

FailedSearchCacheMap::iterator i = map1.begin();
for(; i != map1.end(); i++)
    std::cout << (*i).first << ":" << (*i).second << std::endl;


Test Code Output:

numFailedSearches: 1
map_ptr1 address: 0x909ce88
map_ptr2 address: 0x909ce88
map_ptr1->size(): 0
map_ptr2->size(): 0
map1.size(): 1
map2.size(): 0
hostname:1
+2  A: 

When your test code calls sGetKeyserverFailedSearch(), it is then assigning the pointers to local map variables, thus making copies of the map contents. Any changes you make to those variables will not be reflected in the original maps that you store with pthread_setspecific(), as evident by your logging (map1's size incremented but map_ptr1's size did not). Any modifications you want to make to the original maps must be done using the pointers that sGetKeyserverFailedSearch() returns, for example:

FailedSearchCacheMap* map_ptr = sGetKeyserverFailedSearch();
std::string ks("hostname");

int numFailedSearches = (*map_ptr)[ks] + 1;
(*map_ptr)[ks] = numFailedSearches;

std::cout << "numFailedSearches: " << numFailedSearches << std::endl;
std::cout << "map_ptr address: " << map_ptr << std::endl;
std::cout << "map_ptr->size(): " << map_ptr->size() << std::endl;

FailedSearchCacheMap::iterator i = map_ptr->begin();
for(; i != map_ptr->end(); i++)
    std::cout << (*i).first << ":" << (*i).second << std::endl;
Remy Lebeau - TeamB
Thanks! That's exactly what my problem was. Soon as I started accessing the map using the form (*map)[key] it fixed my problem and all unit tests pass. I'm new to C++ and couldn't figure out how to use the [] operator without first assigning to a local variable.
MrEvil