0

I want to initialize a large number of mutexes for synchronizing threads.

The following syntax causes a build error "Expected expression" inside the loop:

    pthread_mutex_t *mtxs = malloc(MAX * sizeof(pthread_mutex_t));

    for (size_t i=0; i<MAX; i++) {
        mtxs[i] = PTHREAD_MUTEX_INITIALIZER;
    }

I also tried using pointer arithmetic instead of an array:

*(mtxs+i) = PTHREAD_MUTEX_INITIALIZER;

but get the same error.

However, the following code, using 2 steps instead of 1 for the init, works fine:

    pthread_mutex_t *mtxs = malloc(MAX * sizeof(pthread_mutex_t));

    for (size_t i=0; i<MAX; i++) {
        pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;
        mtxs[i] = tmp;
    }

Why does the '1-step' init cause a build error, but '2-step' works fine?

And is there a different syntax for a 1-step init that would work?

matt
  • 90
  • 1
  • 8
  • 1
    You haven't show us what the definition of he `PTHREAD_MUTEX_INITIALIZER` macro is, but I suspect it has a form that includes a `{ ... }` **initializer**. This can *only* be used when actually initializing a variable (in its declaration), not in a later assignment. – Adrian Mole Oct 03 '20 at 19:08
  • 1
    For runtime inits, can you use this instead? [pthread_mutex_init()](https://man7.org/linux/man-pages/man3/pthread_mutex_init.3p.html) – Milag Oct 03 '20 at 19:12
  • 1
    See also this Q/A: https://stackoverflow.com/q/14320041/10871073 – Adrian Mole Oct 03 '20 at 19:14
  • I'm not sure naive copying of mutexes has well-defined behavior. You really ought to use `pthread_mutex_init`. – StoryTeller - Unslander Monica Oct 03 '20 at 19:27
  • Thanks all. You're right, it's better to use ```pthread_mutex_init (&mtxs[i], NULL);``` which also makes it nicely a 1-liner. :) – matt Oct 03 '20 at 19:38

1 Answers1

1

From the man page,

In cases where default mutex attributes are appropriate, the macro PTHREAD_MUTEX_INITIALIZER can be used to initialize mutexes that are statically allocated. The effect shall be equivalent to dynamic initialization by a call to pthread_mutex_init() with parameter attr specified as NULL, except that no error checks are performed.

You can only use PTHREAD_MUTEX_INITIALIZER when initializing a variable. It can't be used in an assignment.

While both use =,

mtxs[i] = PTHREAD_MUTEX_INITIALIZER;

is an expression consisting of an assignment, and

pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;

is a variable declaration with an initializer. There are types of variables (e.g. arrays) that can be initialized, but to which we can't assign.

Furthermore, initializers have a different syntax than what's allowed on the right-hand side of assignment. PTHREAD_MUTEX_INITIALIZER is presumably not valid on the right-hand side of an assignment.

In your failing code, you are using PTHREAD_MUTEX_INITIALIZER in an assignment when it can only be used in an initializer. Use the following instead:

pthread_mutex_init(mtxs+i, NULL);
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • There are definitely types of variables that can be initialized but not assigned to, but structure types are not among them. Structure initializers do have a form that is unsuitable for use in assignment, however. – John Bollinger Oct 04 '20 at 14:20