Linux 信号量信令与互斥

Linux 信号量信令与互斥,linux,synchronization,pthreads,mutex,semaphore,Linux,Synchronization,Pthreads,Mutex,Semaphore,我正在浏览一些描述互斥和二进制信号量之间区别的主题。在许多主题中,信号量充当信号机制,即如果一个线程锁定了一个信号量,那么另一个线程可以解锁(释放)该信号量(充当信号)。 但是在互斥锁的情况下,只有锁定互斥锁的线程才能解锁它。它不能被任何其他线程解锁,如果其他线程试图解锁它,这将返回错误 我尝试过编写一个使用互斥体进行同步的代码。在代码中,我在一个线程中锁定互斥锁,并在另一个线程中成功解锁互斥锁。 有人能解释一下这是怎么发生的吗?根据答案,其他线程应该不能解锁互斥锁 任何建议都是非常受欢迎的。典

我正在浏览一些描述互斥和二进制信号量之间区别的主题。在许多主题中,信号量充当信号机制,即如果一个线程锁定了一个信号量,那么另一个线程可以解锁(释放)该信号量(充当信号)。 但是在互斥锁的情况下,只有锁定互斥锁的线程才能解锁它。它不能被任何其他线程解锁,如果其他线程试图解锁它,这将返回错误

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


任何建议都是非常受欢迎的。

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

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

如果没有更好地理解您的信号需求的性质,我无法以简洁的形式向您提供关于使用什么以及如何实现您的信号的建议

欢迎提出任何建议

对于std::thread和Posix,使用这个Posix进程信号量封装并没有问题

//
#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;
};
//
#include//posix信号量
类PPLSem\u t//Posix进程信号量,设置为本地模式(未命名、非共享)
{
public://not shared-between-process-v--初始值未锁定
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));}//成功时返回0,否则返回-1
int unlock(){return(::sem_post(&m_sem));}//成功时返回0,否则返回-1
私人:
::sem_t m_sem;
};

没有限制哪个线程可以向它发送信号

根据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;
}

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

您似乎对互斥语义有错误的理解;如果在同一线程中锁定互斥锁之前解锁互斥锁,那么您的代码显然是错误的。感谢FooF纠正我的错误。实际上,在同一线程中锁定互斥锁之前,我并没有解锁互斥锁。但在一个线程中,我锁定了它,在另一个线程中,我解锁了它。互斥锁的语义是您锁定了它,然后使用互斥锁所保护的资源执行操作,然后解锁互斥锁。(始终将互斥锁保持在最短时间内-除非您使用递归互斥锁(您几乎永远不应该使用该互斥锁。)如果要在线程之间发送信号,通常使用与互斥锁关联的条件变量。在线上有很多例子,或者获取Butenhof关于Pthreads.for unlock()的优秀书籍。。。“互斥锁必须由当前的执行线程锁定,否则,行为是未定义的。”这意味着任何事情都可能发生,甚至可能看起来它正在工作。还要注意的是,我看到了一些东西,比如从互斥体::unlock()内部进行报告,但不像我预期的那样频繁
tid: 13987 - owner: 13987
tid: 13992 - owner: 13987