Synchronization 进程锁

15 篇文章 0 订阅
  • Boost.Interprocess允许多个进程同时使用共享内存。因为共享内存从定义上来说是进程间共享的,所以Boost.Interprocess需要支持某种同步。
  • 想到同步,我们会想到C++11标准库中的类或Boost.Thread。但是这些类只能用来同步同一进程内的线程,它们不支持不同进程的同步。不过,由于两种情况下面临的挑战是一样的,所以概念也是一样的。
  • 在多线程应用程序中,同步对象(如mutexes和条件变量)驻留在同一个地址空间中,因此所有线程都可以使用,而共享内存的挑战是,独立的进程需要共享这些对象。例如,如果一个进程创建了一个mutex,那么它就需要以某种方式从另一个进程中访问。
  • Boost.Interprocess提供了两种同步对象:匿名对象直接存储在共享内存中,这使得它们对所有进程自动可用。命名对象由操作系统管理,不存储在共享内存中,可以通过名称从程序中引用(named_mutex)

Example 33.12. Using a named mutex with boost::interprocess::named_mutex

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  managed_shared_memory managed_shm{open_or_create, "shm", 1024};
  int *i = managed_shm.find_or_construct<int>("Integer")();
  named_mutex named_mtx{open_or_create, "mtx"};
  named_mtx.lock();
  ++(*i);
  std::cout << *i << '\n';
  named_mtx.unlock();
}
  • Example 33.12 creates and uses a named mutex using the class boost::interprocess::named_mutex, which is defined in boost/interprocess/sync/named_mutex.hpp.
  • boost::interprocess::named_mutex的构造函数期望得到一个参数,指定是否应该创建或打开mutex,以及mutex的名称。每个知道这个名字的进程都可以打开同一个mutex。要访问共享内存中的数据,程序需要通过调用成员函数lock()来获得mutex的所有权。由于mutexes一次只能由一个进程拥有,所以另一个进程可能需要等待,直到mutex被unlock()释放。一旦一个进程拥有了一个mutex的所有权,它就拥有了对mutex所保护的资源的独占性访问权。在示例33.12中,资源是一个类型为int的变量,它被递增并写入标准输出流。
  • 如果示例程序被多次启动,每个实例都会打印一个比前一个值递增1的值。由于有了mutex,不同进程之间对共享内存和变量本身的访问是同步的。

Example 33.13. Using an anonymous mutex with interprocess_mutex

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  managed_shared_memory managed_shm{open_or_create, "shm", 1024};
  int *i = managed_shm.find_or_construct<int>("Integer")();
  interprocess_mutex *mtx =
    managed_shm.find_or_construct<interprocess_mutex>("mtx")();
  mtx->lock();
  ++(*i);
  std::cout << *i << '\n';
  mtx->unlock();
}
  • Example 33.13 uses an anonymous mutex of type boost::interprocess::interprocess_mutex, which is defined in boost/interprocess/sync/interprocess_mutex.hpp. In order for the mutex to be accessible for all processes, it is stored in the shared memory. 
  • 例33.13的行为与前一个完全相同。唯一不同的是mutex,它现在直接存储在共享内存中。这可以通过类 boost::interprocess::managed_shared_memory 中的成员函数 construct() 或 find_or_construct() 来实现。除了lock(),boost::interprocess::named_mutex和boost::interprocess::interprocess_mutex都提供了成员函数try_lock()和timed_lock()。它们的行为与标准库和Boost.Thread中的对应函数完全相同。如果需要递归互斥,Boost.Interprocess提供了两个类:boost::interprocess::named_recursive_mutex和boost::interprocess::interprocess_recursive_mutex

  • 互斥保证了对共享资源的独占访问,而条件变量则控制了谁在什么时候拥有独占访问权。一般来说,Boost.Interprocess提供的条件变量与C++11标准库和Boost.Thread提供的条件变量的工作原理类似。它们具有类似的接口,这使得这些库的用户在Boost.Interprocess中使用这些变量时,会立即感到宾至如归。

Example 33.14. Using a named condition with boost::interprocess::named_condition

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  managed_shared_memory managed_shm{open_or_create, "shm", 1024};
  int *i = managed_shm.find_or_construct<int>("Integer")(0);
  named_mutex named_mtx{open_or_create, "mtx"};
  named_condition named_cnd{open_or_create, "cnd"};
  scoped_lock<named_mutex> lock{named_mtx};
  while (*i < 10)
  {
    if (*i % 2 == 0)
    {
      ++(*i);
      named_cnd.notify_all();
      named_cnd.wait(lock);
    }
    else
    {
      std::cout << *i << std::endl;
      ++(*i);
      named_cnd.notify_all();
      named_cnd.wait(lock);
    }
  }
  named_cnd.notify_all();
  shared_memory_object::remove("shm");
  named_mutex::remove("mtx");
  named_condition::remove("cnd");
}
  • Example 33.14 uses a condition variable of type boost::interprocess::named_condition, which is defined in boost/interprocess/sync/named_condition.hpp. Because it is a named variable, it does not need to be stored in shared memory. 
  • 例33.14使用了一个类型为boost::interprocess::named_condition的条件变量,它定义在boost/interprocess/sync/named_condition.hpp中。因为它是一个命名变量,所以不需要存储在共享内存中。
  • 应用程序使用一个 while 循环来递增一个类型为 int 的变量,该变量存储在共享内存中。虽然变量随着循环的每次迭代而递增,但它只会在每第二次迭代时被写入标准输出流--只写奇数。每当变量递增1时,条件变量命名为_cnd的成员函数wait()被调用。一个锁--在例33.14中,名为锁的变量--被传递给这个成员函数。这是基于RAII的习惯,即在构造函数中取得一个mutex的所有权,并在destructor中释放它。
  • 这个锁是在while循环之前创建的,并且在整个程序执行过程中拥有mutex的所有权。然而,如果将其作为参数传递给wait(),锁就会自动释放。条件变量用于等待指示等待结束的信号。同步是由成员函数wait()和notify_all()控制的。当程序调用wait()时,相应的mutex的所有权被释放。然后,程序会一直等待,直到对同一个条件变量调用notify_all()。启动时,例33.14似乎并没有什么作用。在while循环内将变量i从0增到1后,程序通过调用wait()等待信号。为了发射信号,需要启动第二个程序实例。
  • 第二个实例在进入 while 循环之前,试图取得同一个 mutex 的所有权。由于第一个实例通过调用wait()释放了mutex,所以成功了。因为变量已经被递增了一次,第二个实例执行if表达式的else分支,并将当前值写入标准输出流。然后将值递增1。现在第二个实例也调用wait()。然而,在这之前,它调用notify_all(),这确保了两个实例的正确合作。第一个实例得到通知,并试图再次获得mutex的所有权,而这个mutex仍然由第二个实例拥有。然而,由于第二个实例在调用notify_all()后立即调用wait(),它会自动释放所有权,所以第一个实例将在此时获得所有权。两个实例交替进行,递增共享内存中的变量。但是,只有一个实例将值写入标准输出流。当变量达到值10时,while循环就结束了。为了避免让另一个实例永远等待信号,循环结束后再调用一次notify_all()。在终止之前,共享内存、mutex和条件变量被销毁。
  • 就像有两种类型的mutexes--一种是必须存储在共享内存中的匿名类型,另一种是命名类型--条件变量也有两种类型。例33.15是使用匿名条件变量重写的上一个例子。

Example 33.15. Using an anonymous condition with interprocess_condition

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  managed_shared_memory managed_shm{open_or_create, "shm", 1024};
  int *i = managed_shm.find_or_construct<int>("Integer")(0);
  interprocess_mutex *mtx =
    managed_shm.find_or_construct<interprocess_mutex>("mtx")();
  interprocess_condition *cnd =
    managed_shm.find_or_construct<interprocess_condition>("cnd")();
  scoped_lock<interprocess_mutex> lock{*mtx};
  while (*i < 10)
  {
    if (*i % 2 == 0)
    {
      ++(*i);
      cnd->notify_all();
      cnd->wait(lock);
    }
    else
    {
      std::cout << *i << std::endl;
      ++(*i);
      cnd->notify_all();
      cnd->wait(lock);
    }
  }
  cnd->notify_all();
  shared_memory_object::remove("shm");
}
  • 例33.15的工作原理和上一个完全一样,同样需要启动两次才能将int变量递增十次。除了mutexes和条件变量,Boost.Interprocess还支持semaphores和文件锁。Semaphores与条件变量类似,只是它们不区分两种状态,而是基于一个计数器。文件锁的行为类似于mutexes,只是它们用于硬盘上的文件,而不是内存中的对象。
  • 就像C++11标准库和Boost.Thread区分不同类型的mutexes和锁一样,Boost.Interprocess提供了几种mutexes和锁。例如,mutexes可以是独占的,也可以是非独占的。如果多个进程需要同时读取数据,这很有帮助,因为只需要一个独占的互斥来写入数据。不同的锁类可以将RAII习语应用于单个mutexes。
  • 除非使用匿名同步对象,否则名称应该是唯一的。即使mutexes和条件变量是基于不同类的对象,但对于由Boost.Interprocess封装的操作系统依赖性接口来说,这不一定成立。在Windows上,mutexes和条件变量都使用相同的操作系统函数。如果两个对象使用相同的名称,每种类型的对象都有一个,那么程序在Windows上将无法正常运行。 

参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值