Thread: Should calls to container.end() be syncronized?

  1. #1
    Registered User
    Join Date
    Nov 2006
    Posts
    519

    Should calls to container.end() be syncronized?

    Hi,

    I'm not shure: is the blue version is correct/secure as the red one?

    Code:
    	pthread_mutex_lock(&mEntityTypeMapMutex);
    	std::map<int, std::string>::const_iterator resultCiter = EntityTypeMap.find(entity_se_id);
            pthread_mutex_unlock(&mEntityTypeMapMutex);
    	if(resultCiter == mEntityTypeMap.end())
            {
                    pthread_mutex_unlock(&mEntityTypeMapMutex);
            }
             else
             {
                    pthread_mutex_unlock(&mEntityTypeMapMutex);
             }
    Thank you in advance!

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    it depends on what other threads could do with the map while you are inside the if

    If during your work with resultCiter iterator some other thread could access the map and perform some action that will invalidate the iterator - it is obviously very unsafe to unlock the mutex before you finish your work with the iterator
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    That is true. Let's assume the code inside the if doen't depend on resultCiter.
    Is the comparisation

    Code:
    if(resultCiter == mEntityTypeMap.end())
    itself secure, independend of what other threads might do with the map?

  4. #4
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    I do not know the correct answer, but you always can write code like this

    Code:
    pthread_mutex_lock(&mEntityTypeMapMutex);
    std::map<int, std::string>::const_iterator resultCiter = EntityTypeMap.find(entity_se_id);
    boolean bEnd = (resultCiter == mEntityTypeMap.end());
    pthread_mutex_unlock(&mEntityTypeMapMutex);
    if(bEnd)
    {
    }
    else
    {
    }
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I'd say that .end() is probably a single variable for the map, but it may change at any given time - so for example, if another thread adds an element to the map, that may change the end() - it may only change if it's getting added LAST, but it may also change at any time you add something - I don't know how the implementation of map actually works [it's a binary tree, but what does "end()" mean in this concept - the last element in the map, I presume].

    So what happens if the end() has actually changed, and the comparison isn't true when it would have been true for the find operation? I suspect bad things happen (but I don't know that - I can only guess that you need to treat this specially, and thus the problem would be what happens if end() changed inbetween).

    This in turn makes me think that it's a bad thing

    As an alternative solution, how about copying end() to a "endIter", then unlocking and comparing, e.g.
    Code:
    	pthread_mutex_lock(&mEntityTypeMapMutex);
    	std::map<int, std::string>::const_iterator resultCiter = EntityTypeMap.find(entity_se_id);
    	std::map<int, std::string>::const_iterator endCiter = EntityTypeMap.end();
    
            pthread_mutex_unlock(&mEntityTypeMapMutex);
    	if(resultCiter == endCiter())
    ...
    That way you avoid having two unlock's in different paths of the if/else.

    Now, the question becomes, of course, what happens if more elements are added to the map (or removed) during this point, such that end() is now different [or the map is different in some other way]. Does it matter?

    Let's say this is a check to see if something should be added to the map, what happens if another thread either removes what you just found or adds an element with the same id as you were using in the search - could that happen, and if so, what happens?

    [Who said that threads were easy?]

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Registered User
    Join Date
    Nov 2006
    Posts
    519
    I see. Fortunately my scenario isn't so worst case as Mats describes. So Vart's solution makes my code a bit cleaner.

    Thank you both!

  7. #7
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Code:
            pthread_mutex_unlock(&mEntityTypeMapMutex);
            if (resultCiter == endCiter)
    I'd add that this is making a dangerous assumption - the underlying implementation of resultCiter and endCiter may reference internal state of EntityTypeMap.

    In posix, all multi-threaded access must be synchronized. The only exception to this rule is if multiple threads are only reading shared data that was written prior to the threads starting. If any thread writes data that another thread might read, synchronization must be used.

    When it comes to anything in the std namespace, all access should be done under a mutex. There's no telling when the underlying implementation is going to read or write data.

    gg

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by matsp View Post
    [Who said that threads were easy?]
    It can be easy if you go for the simple solution. In this case, use a single mutex to completely serialize all access to the map. But this can be less efficient than it potentially could be. Most of the complexity in multithread code comes from people's attempts to make things more efficient.

    In this case I would ask why a map is being used and what sort of access behavior is expected.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 26
    Last Post: 07-05-2010, 10:43 AM
  2. System calls in c
    By AmbliKai in forum Linux Programming
    Replies: 2
    Last Post: 03-21-2008, 10:47 AM
  3. Unicode v ANSI Calls
    By Davros in forum Windows Programming
    Replies: 3
    Last Post: 04-18-2006, 09:35 AM
  4. Which I/O calls do you use the most?
    By _Elixia_ in forum Tech Board
    Replies: 10
    Last Post: 07-11-2003, 11:58 AM
  5. C/C++ Memory Calls!
    By Joda in forum C++ Programming
    Replies: 7
    Last Post: 10-25-2002, 04:50 PM