代码之家  ›  专栏  ›  技术社区  ›  fiedel

为什么互斥锁可以被两个线程锁定?

  •  -2
  • fiedel  · 技术社区  · 2 年前

    我的C程序有三个线程 A , B C 共享一些缓冲区。每个缓冲区都受到互斥锁的保护,每个线程在写入/读取缓冲区之前都必须锁定互斥锁。

    A. 写入缓冲区,以及 B C 读取缓冲区。主函数创建 A. ,等待,直到它用锁定第一个缓冲区 pthread_mutex_lock() ,然后创建 B C ,这样缓冲区总是在被读取之前被写入。

    • main.c
    
    #define mutex_lock(mutex, buff_num)        log("wait on buff[%d]\n", buff_num);  \
                                               printf("pthread_mutex_lock returns %d\n", pthread_mutex_lock(mutex));   \
                                               log("buff[%d] locked\n", buff_num)
        
    #define mutex_unlock(mutex, buff_num)      log("releasing buff[%d]\n", buff_num); \
                                               pthread_mutex_unlock(mutex);           \
                                               log("buff[%d] released\n", buff_num)
    
    ...
    typedef struct
    {
        pthread_mutex_t  lock;
        char             data[MAX_DATA_LENGTH];
    } buff_t;
    
    uint8_t A_thread_ready = 0;
    buff_t buff[NUM_BUFF];
    ...
    
    int main()
    {
        ...
        for(int i=0; i<NUM_BUFF; i++)
        {
            if (pthread_mutex_init(&buff[i].lock, NULL) != 0)
            {
                pthread_exit(NULL);
            }
        }
        ...
        status = pthread_create(&tid[0], NULL, &A_thread, NULL);
        if ( 0 == status)
        {
            break;
        }
    
        do
        {
            nanosleep(&t1, &t2);
        } while (0 == A_thread_ready);
    
        status = pthread_create(&tid[1], NULL, &B_thread, NULL);
        if ( 0 == status)
        {
            break;
        }
        ...
    }
    
    • a.c
    ...
    
    extern uint8_t A_thread_ready;
    extern buff_t buff[NUM_BUFF];
    
    ...
    
    void* A_thread(void* arg)
    {
        uint8_t write_buff = 0;
        ...
        mutex_lock(&buff_p->lock, write_buff);
        buff_p = &(buff[write_buff]);
        A_thread_ready = 1;
        while(1)
        {
            ...
            mutex_unlock(&buff_p->lock, write_buff);
            write_buff++;
            write_buff %= NUM_BUFF;
            mutex_lock(&buff_p->lock, write_buff);
            buff_p = &(buff[write_buff]);
            ...
        }
        ...
    }
    
    • b.c
    ...
    
    extern buff_t buff[NUM_BUFF];
    
    ...
    
    void* B_thread(void* arg)
    {
        uint8_t read_buff = 0;
        ...
        mutex_lock(&buff_p->lock, read_buff);
        buff_p = &(buff[read_buff]);
    
        while(1)
        {
            ...
            mutex_unlock(&buff_p->lock, read_buff);
            read_buff++;
            read_buff %= NUM_BUFF;
            mutex_lock(&buff_p->lock, read_buff);
            buff_p = &(buff[read_buff]);
            ...
        }
        ...
    }
    

    然而,当从打印的日志运行程序时,似乎 A. 锁定缓冲器, B 能够锁定相同的缓冲区。

    它做了一些事情,释放了缓冲区。一段时间后 A. 释放了这个缓冲区。我检查了每个的返回值 pthread_mutex_lock() 调用,但始终为0(成功)。我还应该检查什么才能找到这个问题的原因?

    1 回复  |  直到 2 年前
        1
  •  3
  •   Wyck    2 年前

    乍一看,我对这段代码深感担忧:

        mutex_lock(&buff_p->lock, read_buff);
        buff_p = &(buff[read_buff]);
    
        while(1)
        {
            ...
            mutex_unlock(&buff_p->lock, read_buff);
    

    看起来你确实锁定了存储在 buff_p->lock (缓冲区1的锁),那么你 改变 buff_p 的值 buff_p = &(buff[read_buff]); ,然后解锁 其他一些互斥 :处的互斥 buff_p->锁 (缓冲器2的锁)。大概这些是完全不同缓冲区上的不同锁。