信号量信令与互斥量

时间:2017-03-30 20:49:07

标签: linux synchronization pthreads mutex semaphore

我正在研究一些描述互斥量和二进制信号量之间差异的主题。在许多主题中,声明信号量充当信令机制,即如果线程已锁定信号量,则另一线程可以解锁(释放)信号量(充当信号)。 但是在互斥锁的情况下,只有锁定互斥锁的线程才能解锁它。它不能被任何其他线程解锁,如果其他线程试图解锁它,这将返回错误。

我尝试编写使用互斥锁进行同步的代码。在代码中,我将互斥锁定在一个线程中,并成功解锁其他线程中的互斥锁。 有人可以解释一下这是怎么发生的。根据各地的答案,其他线程不应该能够解锁互斥锁。

欢迎任何建议。

3 个答案:

答案 0 :(得分:0)

典型的POSIX线程实现不执行任何检查或验证,即解锁互斥锁的线程与锁定互斥锁的线程相同(或者甚至可能首先锁定互斥锁)。这不是互斥体的使用方式。 “互斥”一词意味着相互排斥;该概念的目的是为多线程提供一种机制,以便在没有其他线程干扰的情况下安全地访问或修改资源(例如数据结构),并且在完成修改时,在解锁互斥锁之前使资源处于一致状态。

在运行时捕获这样的编程错误可能会很好(就像捕获超出对数组的写入一样),但是默认情况下提供这样的簿记和保护太昂贵了性能;互斥锁定和解锁操作应该为您提供最小的开销,使它们可以使用。这就是您成功从错误的线程中解锁互斥锁的原因。在标准的Linux pthread实现中,您可以使用“错误检查”互斥锁,当您尝试从错误的线程解锁互斥锁时会出现错误,但此检查仅用于捕获编程错误。

我无法以紧凑的形式建议您使用什么以及如何在不更好地了解信号需求性质的情况下实施信号。

答案 1 :(得分:0)

  

欢迎任何建议。

对于std :: thread以及posix,我使用这个Posix Process Semaphore封装没有任何问题。

//
#include <semaphore.h>  // posix semaphore

class PPLSem_t // Posix Process Semaphore, set to Local mode (unnamed, unshared)
{
public: //           not shared-between-process-v  v--initial-value-unlocked
   PPLSem_t()   { int stat = ::sem_init(&m_sem, 0, 1);  assert(0 == stat); } // ctor
   ~PPLSem_t()  { int stat = ::sem_destroy(&m_sem);     assert(0 == stat); } // dtor

   int lock()   { return (::sem_wait(&m_sem)); }   // returns 0 when success, else -1
   int unlock() { return (::sem_post(&m_sem)); }   // returns 0 when success, else -1
private:
   ::sem_t m_sem;
};

没有限制哪个线程可能发出信号。

答案 2 :(得分:0)

根据pthread_mutex_lock手册页:如果互斥锁类型为PTHREAD_MUTEX_DEFAULT,如果未通过调用线程锁定互斥锁,则尝试解锁互斥锁会导致未定义的行为。如果未锁定互斥锁,则尝试解锁互斥锁会导致未定义的行为。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <syscall.h>

pthread_mutex_t mutex;

void *thread(void *ptr)
{
    int ret = pthread_mutex_unlock(&mutex);

    if (!ret)
    {
        printf("error unlocking: %s", strerror(errno));
    }

    printf("tid: %u - owner: %u\n", syscall(SYS_gettid), mutex.__data.__owner);

    return NULL;
}

int main()
{
    pthread_t thread1;
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
    pthread_mutex_init(&mutex, &attr);
    pthread_mutexattr_destroy(&attr);

    pthread_mutex_lock(&mutex);

    printf("tid: %u - owner: %u\n", syscall(SYS_gettid), mutex.__data.__owner);

    pthread_create(&thread1, NULL, thread, NULL);

    pthread_join(thread1, NULL);

    return 0;
}

为我输出:

tid: 13987 - owner: 13987
tid: 13992 - owner: 13987

互斥信号和二进制信号量之间的唯一区别是所有者概念。互斥有一个拥有者,所以你必须&#34;必须&#34;在同一个线程中锁定并解锁它,但您可以在不同的线程中发布或等待信号量。