首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >确定对函数的并发访问

确定对函数的并发访问
EN

Code Review用户
提问于 2019-06-07 06:17:24
回答 1查看 207关注 0票数 4

有人问这里如何确定从多个线程调用的函数。我对此的看法是,他们询问的是并发访问,而不是顺序访问。因此,接受的答案似乎是不充分的。为了调试目的,检测并发访问也是我需要解决的问题,所以我想尝试一种解决方案。

这需要采用RAII风格的方法来解决方案,只需要在所讨论的函数顶部实例化类。

代码语言:javascript
运行
复制
template <std::ostream& stream> class ConcurrentPrint: public std::ostringstream
{
public:
    ~ConcurrentPrint()
    {
        std::scoped_lock lock(printMutex);
        stream << this->str();
    }

private:
    static std::mutex printMutex;
};

template <std::ostream& stream> std::mutex ConcurrentPrint<stream>::printMutex;

class ConcurrencyChecker
{
public:

    ConcurrencyChecker(const std::string& id_) :
    id(id_)
    {
        std::scoped_lock lock(mapMutex);
        if (++numInstances[id] > 1)
        {
            ConcurrentPrint<std::cerr>() << "Warning: concurrent access to " << id << " from " << std::this_thread::get_id() << std::endl;
            abort();
        }
    }

    ~ConcurrencyChecker()
    {
        std::scoped_lock lock(mapMutex);
        --numInstances[id];
    }

private:
    static std::map<std::string, int> numInstances;
    static std::mutex cerrMutex;

    const std::string id;
    std::mutex mapMutex;
};

std::map<std::string, int> ConcurrencyChecker::numInstances = {};

预期用途:

代码语言:javascript
运行
复制
void functionToCheck()
{
    ConcurrencyChecker check(__func__);

    /* Function body */
}

工作实例这里

我感兴趣的事情:

  • 这种一般做法是否有任何缺陷,是否有更好的办法?
  • 对代码的任何一般改进
EN

回答 1

Code Review用户

发布于 2019-06-07 07:37:31

我头上有几个观察

cerrMutex是未使用的,如果不需要,应该删除它。

mapMutex用于保护静态std::map,但它本身是一个常规类成员变量。这表明,它可能并不是在保护地图以防止并发访问。这可能是个窃听器。

这似乎是一个相当重量级的工具。地图和字符串的使用闻起来都有点臃肿。这本身并不是一个杀手,但至少值得注意。如果有可能仅仅使用对象-局部整数来计数(或者使用函数作用域静态声明来使用相同的计数变量),那么这可能会更轻。

另一方面,在一般用例中,当两个线程与同一个资源交互时,并发性会导致问题,而不仅仅是在执行相同的函数时。例如,如果该工具能够检测到同时运行单个对象的两个方法的不同线程,那么它将非常有用。

同时,如果它实际上不干扰两个线程--每个线程都包含给定类的自己的对象和每个在自己的对象上运行的方法--将会更有帮助。这也许更像是一种文档增强建议:您的粗略方法可以通过更改您传递的ID来工作,但它将从示例中受益。(如果这意味着失去了这样做的能力,就不要改变它使其变得轻量级!)

最后一件值得思考的事情是,这是否会导致任何无意中的同步,而这实际上掩盖了您正试图检测到的问题。这是很难预测的,因为调度程序在一般情况下可能是一种黑暗的艺术,但是您可能会遇到这样的问题。

假设有两个线程运行一个函数,该函数执行一些轻量级的操作,可能只是增加一个共享整数。如果没有这个工具,你就会期望他们不断地踩在对方身上。

因为您在mapMutex上同步(我将假设它是静态的),所以对函数的每个调用都必须在工具的构造函数和析构函数中做很多额外的工作,这都是排除在外的。如果线程2在线程1仍在构造函数中时启动,它将无法接受mapMutex,调度程序可能会将其发送到睡眠状态。用于唤醒线程1的窗口实际上非常小,其中线程1位于函数中,没有互斥体。那么,您可以得到的是,在此对象试图帮助调试时,该函数的行为似乎很好(尽管速度很慢),然后在删除调试对象时返回数据竞赛以进行发布代码。我只想说,这没什么用!

对于如何解决这个问题,我没有任何建议,只是这是值得注意的事情。

票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/221831

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档