【问题标题】:Is it safe to call pthread_mutex_lock before pthread_mutex_init?在 pthread_mutex_init 之前调用 pthread_mutex_lock 是否安全?
【发布时间】:2015-10-18 06:45:11
【问题描述】:

我以前从未有机会使用 pthreads 库,但我正在审查一些涉及 pthread 互斥锁的代码。我检查了pthread_mutex_lockpthread_mutex_init 的文档,通过阅读这两个函数的手册页我的理解是,我必须在调用pthread_mutex_lock 之前调用pthread_mutex_init

但是,我问了几个同事,他们认为可以先拨打pthread_mutex_lock,然后再拨打pthread_mutex_init。我正在审查的代码也调用了pthread_mutex_lock,甚至没有调用pthread_mutex_init

基本上,在调用pthread_mutex_init 之前调用pthread_mutex_lock 是否安全且明智(如果pthread_mutex_init 甚至被调用)?

编辑:我还看到了一些在不使用pthread_mutex_init 时调用pthread_mutex_lock 的示例,例如this example

编辑#2:这是我正在审查的具体代码。请注意,配置函数获取并附加到一些未初始化的共享内存。稍后的 Java 代码将调用 lock(),中间不会调用其他本机函数。 Link to code

【问题讨论】:

  • 当然当然你不应该在未初始化的情况下使用它......就像任何其他未初始化的数据一样。但是,有一些方法可以在不调用 pthread_mutex_init() 的情况下初始化互斥锁(例如 PTHREAD_MUTEX_INITIALIZER 宏)
  • 在您链接到的示例中,他们在文件范围内声明互斥锁,因此将其清零......他们可能假设清零 pthread_mutex_t 是一个有效状态已解锁的互斥锁...或未显示初始化代码。
  • 我明白了。抱歉,我刚刚添加了第二次编辑。看起来我正在审查的代码也做了类似的事情,因为 shmget 应该将内存区域清零。即使在这些情况下,调用 pthread_mutex_init 仍然是个好主意吗?
  • 清零的pthread_mutex_t其实是一个有效的状态,但是按照标准,mutex必须初始化,所以使用PTHREAD_MUTEX_INITIALIZER或者pthred_mutex_init()
  • 我要么打电话给pthread_mutex_init(),要么至少使用例如。 pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER;

标签: c pthreads mutex


【解决方案1】:

这是我在评论中发布的链接中的文字:

 Mutual exclusion locks (mutexes)  prevent  multiple  threads
 from simultaneously executing critical sections of code that
 access shared data (that is, mutexes are used  to  serialize
 the  execution  of  threads).  All mutexes must be global. A
 successful call for a mutex lock  by  way  of   mutex_lock()
 will  cause  another  thread that is also trying to lock the
 same mutex to block until the owner thread unlocks it by way
 of   mutex_unlock().  Threads  within  the  same  process or
 within other processes can share mutexes.

 Mutexes can synchronize threads within the **same  process**  or
 in  ***other   processes***.  Mutexes  can  be used to synchronize
 threads between processes if the mutexes  are  allocated  in
 writable  memory  and shared among the cooperating processes
 (see mmap(2)), and have been initialized for this task.

Initialize Mutexes are either intra-process or inter-process,
depending upon the argument passed implicitly or explicitly to the initialization of that mutex.
A statically allocated mutex does not need to be explicitly initialized;
by default, a statically allocated mutex is initialized with all zeros and its scope is set to be within the calling process.

 For inter-process synchronization, a mutex needs to be allo-
 cated   in  memory shared between these processes. Since the
 memory for such a mutex must be allocated dynamically,   the
 mutex needs to be explicitly initialized using mutex_init().




also, for inter-process synchronization,
besides the requirement to be allocated in shared memory,
the mutexes must also use the attribute PTHREAD_PROCESS_SHARED,
otherwise accessing the mutex from another process than its creator results in undefined behaviour
(see this: linux.die.net/man/3/pthread_mutexattr_setpshared):

The process-shared attribute is set to PTHREAD_PROCESS_SHARED to permit a
mutex to be operated upon by any thread that has access to the memory
where the mutex is allocated, even if the mutex is allocated in memory that is shared by multiple processes

【讨论】:

    【解决方案2】:

    POSIX standard 说:

    如果mutex 不引用已初始化的互斥对象,则行为 pthread_mutex_lock()pthread_mutex_trylock()pthread_mutex_unlock() 未定义。

    所以您确实需要初始化互斥锁。这可以通过调用pthread_mutex_init() 来完成;或者,如果互斥体具有静态存储持续时间,则使用静态初始化程序 PTHREAD_MUTEX_INITIALIZER。例如:

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    

    【讨论】:

      【解决方案3】:

      互斥体是包含函数完成其工作所需的状态(信息)的变量。如果不需要信息,则例程不需要变量。同样,如果您向其提供随机垃圾,该例程可能无法正常运行。

      大多数平台都接受一个用零字节填充的互斥对象。这通常是 pthread_mutex_initPTHREAD_MUTEX_INITIALIZER 创建的。碰巧的是,C 语言还保证在程序启动时将未初始化的全局变量清零。因此,看起来您不需要初始化pthread_mutex_t 对象,但事实并非如此。尤其是位于堆栈或堆中的东西通常不会被归零。

      调用pthread_mutex_init 之后 pthread_lock 肯定会产生不良后果。它将覆盖变量。潜在结果:

      1. 互斥锁被解锁。
      2. 另一个线程试图获取锁的竞争条件导致崩溃。
      3. 库或内核中泄漏的资源(但将在进程终止时释放)。

      【讨论】:

      • 非常感谢。我将在稍后审查的代码上打开一个拉取请求。它现在可能没有多大作用,但至少它会在未来提高代码质量并降低风险。
      猜你喜欢
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 2020-12-09
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      • 1970-01-01
      • 2012-07-09
      相关资源
      最近更新 更多