【问题标题】:Unlocking a mutex after calling trylock()调用 trylock() 后解锁互斥锁
【发布时间】:2015-01-16 09:16:27
【问题描述】:

我有一个线程服务器,可以添加/附加/读取文件并将数据中继到客户端。

如果正在添加文件,则没有其他线程可以附加/读取它。如果正在附加文件,则没有线程可以附加/读取它。如果正在读取文件,则没有其他线程可以附加到它。但是,如果一个文件正在被读取,其他文件可以读取它。

目前我有一个互斥系统可以执行此操作,但它不允许多次读取。

为了解决这个问题,我将在 read 方法中进行更改:

pthread_mutex_lock(&(fm->mutex));//LOCK
//do some things`
...
pthread_mutex_unlock(&(fm->mutex));

pthread_mutex_trylock(&(fm->mutex));//TRYLOCK [NonBlocking, so the thread can continue the read]
//do some things`
...
pthread_mutex_unlock(&(fm->mutex));

问题

如何在所有其他 read() 完成之前不让其他方法(实际上只是追加)开始写入文件的情况下解锁文件?

示例

例如,如果最初锁定文件的读取线程完成并解锁文件,并且还有其他线程试图读取文件,则附加线程有机会锁定文件并开始附加,而其他线程正在仍在阅读,这是一个禁忌。

想法

我想记录当前读取文件的线程数。当一个线程完成时,减少计数。如果计数为 0,表示没有线程仍在读取,则解锁文件。但是,我担心这不是线程安全的。如果这是一个可行的解决方案,我怎样才能使它成为线程安全的?另一个但是,我相信只有原始线程才能成功解锁互斥锁。

【问题讨论】:

  • 听起来你可能正在寻找一个读写锁,由pthreads提供:docs.oracle.com/cd/E19455-01/806-5257/6je9h032t/index.html
  • 一个文件可以有多少个状态?在我看来,至少需要三种状态,“已添加”(添加该文件后的状态)、“附加”(添加该文件后的状态”和“读取”(添加该文件后的状态)。一个互斥锁可能不足以控制三个状态。
  • @Fumu Add/Append 本质上是相同的,不应将它们视为单独的状态。只有读取是不同的,所以我想说这里仍然只有两个状态。
  • @JeremyFriesner 那不是 pthread 链接......但现在在 pthreads 中搜索。编辑:哎呀,只是一个例子链接到其他地方,没有使用 pthreads。
  • @JeremyFriesner 如果您愿意,可以将其添加为答案,我现在已经有了工作代码,只需进行很少的更改即可使其运行。谢谢!

标签: c linux pthreads mutex


【解决方案1】:

您可以使用信号量代替互斥锁(请参阅this link 了解差异)。信号量为您执行线程安全的同步计数。

如果您将同时读取访问的数量限制为(足够大的)数字 N 并要求信号量增加该数量以进行写入访问,那么您可以无需额外的互斥锁来锁定文件以进行写入。这样,只有在读者数量为零的情况下,您才能获得写访问权限,并且所有其他读者将被锁定,直到您的作者完成为止。

【讨论】:

  • 听起来可以。我有@JeremyFriesner 的建议工作,幸运的是这是一个更简单的解决方案。我确实想知道这是否就是该功能的实现方式。
  • 信号量是最容易以线程安全的方式对事物进行计数(并且它们在 pthreads 中实现)。由于您需要跟踪并发读者的数量,我敢打赌他们就是这样做的。给自己的心理提示:你必须有一天查一下这件事。
【解决方案2】:

听起来您可能正在寻找由 pthreads 提供的read-write lock。它允许两种锁定模式:共享/读锁定模式,可以同时被多个线程锁定,以及独占/写锁定模式,在所有其他线程(读取器和写入器)之前,锁定调用不会返回) 已经放弃了对锁的控制。

【讨论】:

    【解决方案3】:

    请注意,pthread_mutex_lock() 的 POSIX 文档说:

    如果成功,pthread_mutex_lock()pthread_mutex_trylock()pthread_mutex_unlock()函数应返回零;否则,将返回错误号以指示错误。

    由于您没有显示测试返回值的代码,因此您不知道您的锁定操作(特别是)是否成功。

    另外,既然你想要一个读/写锁,为什么不使用一个:

    pthread_rwlockattr_*()函数有4个,pthread_rwlock_*()函数一共9个;我只列出了家族中最重要的功能。

    【讨论】:

      猜你喜欢
      • 2018-05-23
      • 1970-01-01
      • 2022-07-31
      • 2013-02-02
      • 2010-11-22
      • 1970-01-01
      • 2021-12-23
      • 2019-11-01
      相关资源
      最近更新 更多