【问题标题】:Using a pointer to a Mutex (pthread_mutex_t *) in a structure, Instead of a global Mutex在结构中使用指向互斥锁 (pthread_mutex_t *) 的指针,而不是全局互斥锁
【发布时间】:2022-01-19 14:26:27
【问题描述】:

我在启动多个线程的程序中使用了锁 (pthread_mutex_t),所有线程都会收到一个指向结构的指针,该结构包含指向该互斥锁的指针。

所以有一个已初始化的互斥体,所有结构都有一个指向它的指针,但它不能很好地工作,我不明白为什么?

这里是一些示例代码,我尽量减少它。

让我们调用我的程序duck:

duck.c

# include "duck.h"

void    *exec_threads(void *arg)
{
    struct s_duck   *duck;

    duck = (struct s_duck*)arg;
    pthread_mutex_lock(duck->mutex);
    printf("duck nbr %i\n", duck->n);
    pthread_mutex_unlock(duck->mutex);
    return (NULL);
}

int main(void)
{
    pthread_t       *id;
    pthread_mutex_t *mutex;
    struct s_duck   *duck;
    int             n;
    int             i;

    n = 5; // number of threads
    id = malloc(sizeof(int) * n); // allocate id[n]
    mutex = malloc(sizeof(pthread_mutex_t)); // allocate mutex
    pthread_mutex_init(mutex, NULL); // init mutex
    duck = init_chain_ducks(mutex, n); // create chained list of structure
    i = 0;
    while (i < n)
    {
        pthread_create(&id[i], NULL, &exec_threads, duck); // launch threads
        duck = duck->next;
        i++;
    }
    i = 0;
    while (i < n)
    {
        pthread_join(id[i], NULL); // join threads
        i++;
    }
    write(1, "the end\n", 8);
    return (0);
}

duck_chain.c

# include "duck.h"

struct s_duck   *init_chain_ducks(pthread_mutex_t *mutex, int n)
{   
    struct s_duck   *new;
    struct s_duck   *duck;
    int         i;

    i = n;
    duck = NULL;
    while (i > 0)
    {
        new = malloc(sizeof(struct s_duck));
        new->n = i;
        new->mutex = mutex; // this is where the pointer to the mutex is stored
        new->next = duck;
        duck = new;
        i--;
    }
    return (duck);
}

duck.h

#ifndef DUCK_H
# define DUCK_H

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <pthread.h>

struct s_duck
{
    int             n;
    pthread_mutex_t *mutex;
    struct s_duck   *next;
};

struct s_duck   *init_chain_ducks(pthread_mutex_t *mutex, int n);

#endif

如果我对互斥锁使用全局变量,它会很好地工作。但是使用结构中的指针,我会得到类似未定义的行为:

大多数时候我得到这个输出:

duck nbr 1
duck nbr 3
duck nbr 4
duck nbr 5
duck nbr 2
[2]    18914 segmentation fault (core dumped)  ./a.out

段错误发生在pthread_join() 期间,但我也经常遇到这两个错误:

duck nbr 1
duck nbr 2
[wait indefinitely]

或者:

duck nbr 1
duck nbr 4
duck nbr 3
a.out: ../nptl/pthread_mutex_lock.c:81: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
[2]    20394 abort (core dumped)  ./a.out

我一定是犯了一些基本错误,但我不知道在哪里。

(编译:gcc duck.c duck_chain.c -lpthread

【问题讨论】:

  • 请注意,尽管您的结构可以包含pthread_mutex_t *,您的线程可以通过该pthread_mutex_t * 访问互斥锁,但这在间接级别上似乎有点过分。一种可能的替代方法是为您的结构提供pthread_mutex_t 类型的成员,而不是指向一个成员的指针。当互斥体的目的是保护结构的其他成员时,这特别有意义,但不限于这种情况。
  • 好的,但是这里每个线程都接收到不同的结构(它是一个链表,元素比线程多),所以如果它们包含一个pthread_mutex_t,那不起作用?还是我错过了什么?
  • 你是对的。如果每个线程接收到不同的结构,但它们需要访问同一个互斥锁,则该互斥锁本身不能成为该结构的成员,而指向它的指针可以。我想用你的代码我会坚持使用全局互斥锁,或者创建一个更高级别的结构来表示整个链表,并将互斥锁放在那里。
  • a higher-level structure to represent the whole linked list,是的,我确实可以这样做

标签: c pthreads mutex


【解决方案1】:
pthread_t       *id;

id = malloc(sizeof(int) * n); // allocate id[n]

id 不是int - 它是pthread_t。应该是sizeof(pthread_t)。使用一个小技巧,并使用指针指向。

id = malloc(sizeof(*id) * n);

使用 -g -Wall -Wextra -fsanitize=undefined,address 编译 - 消毒剂将帮助您发现此类错误。

【讨论】:

  • 谢谢,就是这样!并感谢提示(我实际上使用 -Wall -Wextra 和 -Werror,我没有提到它,但我大部分时间不使用 -fsanitize,我现在会使用)。不过我很困惑,为什么当我使用这个版本的全局互斥锁时没有发生问题,因为问题毕竟不是互斥锁?
  • 变量在不同的地方,碰巧在((int*)id)[n]那里什么都没有,所以它没有被发现。
  • 所以是偶然的?我不这么认为,我的意思是,我测试了很多时间,这不仅仅是一次性的危险。它系统地与我的错误一起工作,但是对互斥变量的全局声明,并且由于我的错误,它在没有全局声明的情况下系统地失败。但是我的错误与全局变量无关,所以我不明白这个(我不需要,只是好奇)
  • So it was by chance ? 你写了无效的代码,发生的一切都是“偶然的”,它偶然起作用,偶然失败。 has nothing to do with the global variable 您的代码越界写入分配的内存,无论“之后”内存被覆盖。您没有显示您的其他代码 - 我怀疑编译器在被覆盖的区域中没有放置任何相关的内容,错误未被检测到。
  • 不——“就这么发生了”不是保证。在您的代码中有线程,它们是无序的,因此它们中的任何一个都可以先执行或与其他线程同时执行,从而产生不同的输出。真的,对无效代码(关于“未定义行为”)进行推理是没有意义的——你唯一能做的就是检查实际的汇编代码,看看会发生什么。
猜你喜欢
  • 2021-08-19
  • 2012-06-05
  • 1970-01-01
  • 2018-05-23
  • 2019-03-21
  • 2013-01-15
  • 2014-09-26
  • 2010-09-16
  • 1970-01-01
相关资源
最近更新 更多