优雅的断言函数不是从多个线程调用的

Posted

技术标签:

【中文标题】优雅的断言函数不是从多个线程调用的【英文标题】:Elegant assert that function is not called from several threads 【发布时间】:2018-02-21 16:28:31 【问题描述】:

我有一个不能同时从多个线程调用的函数。你能为此提出一些优雅的断言吗?

【问题讨论】:

人们认为的“优雅”完全是基于意见的。 std::mutex with try_lock 无论如何,你想要断言它是什么意思? “没有同时从多个线程调用”是什么意思?您的意思是在同一时间,还是无论何时只有一个线程应该调用该函数?如果是前者,你应该使用某种锁/互斥锁。如果是后者,您可以只检查调用函数的线程的 id,或者只将函数放在一个线程的范围内(如果可能的话)。 这听起来像是试图绕过设计错误进行编码。 【参考方案1】:

您可以在std::atomic<> 周围使用薄的 RAII 包装器:

namespace 
    std::atomic<int> access_counter;

    struct access_checker 
        access_checker()  check = ++access_counter; 
        access_checker( const access_checker & ) = delete;
        ~access_checker()  --access_counter; 
        int check;
    ;



void foobar()

     access_checker checker;
     // assert than checker.check == 1 and react accordingly
     ...

它是单一使用的简化版本,以展示想法,如果需要,可以改进以用于多种功能

【讨论】:

甚至可能在构造函数中断言。我还将计数器设为结构的静态成员以防止修补。 唯一的缺点是这会给使用该函数的顺序代码带来开销。但它可以很容易地转化为基于策略的设计,并将不作为策略定义为默认值。【参考方案2】:

听起来你需要一个互斥锁。假设您使用的是std::thread,您可以查看以下链接中的编码示例,以专门使用std::mutex:http://www.cplusplus.com/reference/mutex/mutex/

// mutex example
#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex

std::mutex mtx;           // mutex for critical section

void print_block (int n, char c) 
  // critical section (exclusive access to std::cout signaled by locking mtx):
  mtx.lock();
  for (int i=0; i<n; ++i)  std::cout << c; 
  std::cout << '\n';
  mtx.unlock();


int main ()

  std::thread th1 (print_block,50,'*');
  std::thread th2 (print_block,50,'$');

  th1.join();
  th2.join();

  return 0;

在上面的代码中print_block锁定mtx,做它需要做的,然后解锁mtx。如果从两个不同的线程调用print_block,一个线程将首先锁定mtx,另一个线程将阻塞mtx.lock(),并强制等待直到另一个线程调用mtx.unlock()。这意味着只有一个线程可以同时执行mtx.lock()mtx.unlock()(不包括)之间的代码。

这假设“同时”是指在同一时间。如果您只希望一个线程能够调用一个函数,我建议您查看std::this_thread::get_id,它将为您提供当前线程的 id。断言可以简单到将拥有的线程存储在owning_thread_id 中,然后调用assert(owning_thread_id == std::this_thread::get_id())

【讨论】:

该函数不打算从多个线程中使用,但可能会被意外使用,因为环境是高度并行的。我不需要锁定。这应该是一个检查或联系,它不应该从多个线程中使用。 @BransDs 要可靠地检查多线程访问,您必须使用线程原语,互斥或原子 我明白了。我假设你的意思是我解释你的问题在 OP 中可能意味着的前者。我在案例中编辑了后一种解释,这似乎是你想要问的。希望对您有所帮助。 OP 不想同时访问,OP 希望确保它不会发生。您的互斥锁解决方案没有解决这个问题。 我喜欢线程 ID 的想法,但是请注意,您需要通过互斥锁保护对 owning_thread_id 的读写。否则,就会出现数据竞争。

以上是关于优雅的断言函数不是从多个线程调用的的主要内容,如果未能解决你的问题,请参考以下文章

C++,多线程,线程中调用的函数能不能直接使用线程中定义的变量?

每次调用fork()函数之后,父线程和创建出的子线程都是从fork()后开始执行

python 多个装饰器的调用顺序

可重入和线程安全

请问能够实现在UNIX下,一个进程下创建两个线程调用多个函数的问题

多个线程使用不同的参数值集调用相同的函数