繁体   English   中英

在多线程环境中从STL Map读取/写入

[英]Reading/Writing from STL Map in multithreaded environment

问题:我需要编写一个函数,该函数从映射返回输入键的值。 如果函数在map中找不到值,它将从数据库中获取该值,写入map以供将来使用并返回相同值。 可以有多个线程调用此函数。

我在想这条线:

string GetData (const int key)
{

    pthread_rwlock_rdlock(&rwlock); //read lock
    string result = "not found";
    my_map::const_iterator iter = m.find(key);
    if ( iter != m.end() )//found
    {
       result = iter->second;
    }
    else //missing
    {
        pthread_rwlock_wrlock(&rwlock); // write lock
        //fetch value from data base


        //if successful, add to the map
          m[key] = "missing data";
          result = "missing data";
     pthread_rwlock_unlock(&rwlock); // unlock write lock
    }
    pthread_rwlock_unlock(&rwlock); // unlock read lock
    return result;
}

这个函数线程安全吗? 两个或更多线程是否有可能在写锁上排队并从数据库查询同一密钥? 如果是,如何避免这种情况?

此函数不是线程安全的,因为它会导致未定义的行为。 当您尝试获取写锁时,您已经持有一个读锁。 pthread_rwlock_wrlock的文档中:

如果在调用[ pthread_rwlock_wrlock ]时调用线程持有读写锁(无论是读锁还是写锁),则结果不确定。

此解决方案也不是异常安全的。 如果在持有该锁的同时抛出异常,则该锁将不会被释放,并且您的应用程序无疑会死锁。 您应该使用C ++线程库(Boost.Thread,OpenThreads,just :: thread或类似的东西),该库提供面向C ++的设计,支持诸如scoped_lock (或lock_guard )之类的东西。

为了使算法正确,您需要遵循以下原则:

obtain read lock
attempt to find object
if object exists
    return object
else
    release read lock
    obtain write lock
    if object exists
        return object
    else
        insert object
        return object

[如果使用某种lock_guard ,则不必担心在返回时释放持有的锁]

实施不正确。 担心保持死锁状态,您在持有读锁的同时不能使用写锁。 在我的Linux机器上的pthread_rwlock_wrlock手册页中:

pthread_rwlock_wrlock()函数应将写锁应用于rwlock引用的读写锁。 如果没有其他线程(读取器或写入器)持有读写锁rwlock,则调用线程将获得写入锁。 否则,线程将阻塞直到可以获取锁为止。 如果在调用时它拥有读写锁(无论是读锁还是写锁),则调用线程可能会死锁。

此外,您应该检查调用的返回值...例如,同时读取器的数量有一个实现定义的限制。

还有一些异常安全性的常见问题...考虑一下示波器保护或try / catch块。

获得写锁定后,您可以修复它以再次寻找该值。 这应该足以解决您正在描述的问题。 就像是:

string GetData (const int key)
{

    pthread_rwlock_rdlock(&rwlock); //read lock
    string result = "not found";
    my_map::const_iterator iter = m.find(key);
    if ( iter != m.end() )//found
    {
        result = iter->second;
    }
    else //missing
    {
        // change from read mode to write mode
        pthread_rwlock_unlock(&rwlock); // unlock read lock
        pthread_rwlock_wrlock(&rwlock); // write lock

        // Try again
        iter = m.find(key);
        if (iter != m.end()) {
            result = iter->second;
        } else {
            //if successful, add to the map
            m[key] = "missing data";
            result = "missing data";
        }
    }
    pthread_rwlock_unlock(&rwlock); // unlock read/write lock
    return result;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM