1

I've use pthread for multithreded program and I've got the following situation. When I run the code without sleep command it causes error at run time, and when I add the sleep command program runs as expected.

With sleep:

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



pthread_mutex_t m_writer = PTHREAD_MUTEX_INITIALIZER;

void *print_str(void *args) {
  sleep(12);
  char *str = (char*) args;
  pthread_mutex_lock(&m_writer);
  printf("%s", str);
  pthread_mutex_unlock(&m_writer);
  pthread_exit(NULL);
}

int main(int argc, char **argv) {
  pthread_t t1;
  pthread_create(&t1, NULL, print_str, "Hello\n");
  pthread_mutex_lock(&m_writer);
  printf("LOL\n");
  pthread_mutex_unlock(&m_writer);
  pthread_join(t1, NULL);
  return 0;
}

Without sleep:

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



pthread_mutex_t m_writer = PTHREAD_MUTEX_INITIALIZER;

void *print_str(void *args) {
  char *str = (char*) args;
  pthread_mutex_lock(&m_writer);
  printf("%s", str);
  pthread_mutex_unlock(&m_writer);
  pthread_exit(NULL);
}

int main(int argc, char **argv) {
  pthread_t t1;
  pthread_create(&t1, NULL, print_str, "Hello\n");
  pthread_mutex_lock(&m_writer);
  printf("LOL\n");
  pthread_mutex_unlock(&m_writer);
  pthread_join(t1, NULL);
  return 0;
}

Error:

futex(0x559c3d3df0a0, FUTEX_WAIT_PRIVATE, 2, NULLHello ) = -1 EAGAIN (Resource temporarily unavailable)

Matan
  • 43
  • 6
  • EAGAIN - The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded. When you sleep main function thread succeed to lock and unlock mutex before it locked by another thread. You use ONE mutex in TWO different pieces of code (which is shared source). That is - in general - wrong. If you want to test printf buffering queue then make two separate threads which will call print_str. – Ivan Ivanov Jan 04 '18 at 07:09
  • How do you know there's an error? Your code doesn't check for errors. – n. m. could be an AI Jan 04 '18 at 07:20
  • I've checked it with strace.@n.m. – Matan Jan 04 '18 at 07:21
  • @IvanIvanov A mutex protects a shared resource from concurrent access. It doesn't matter how many places in the code try to access the resource. If it's the same resource it ought to be the same mutex. – n. m. could be an AI Jan 04 '18 at 07:25
  • Great, now throw away your strace log because it has zero meaning, and insert error checks in the code. – n. m. could be an AI Jan 04 '18 at 07:26
  • ... because strace shows you results of system calls. Pthread functions in Linux are not system calls, they are libc functions implemented on top of (potentilally non-trivial) system calls. You are not interested in what internal system calls return. A single successfull call to ptread_mutex_lock may and does entail several failing syscalls. – n. m. could be an AI Jan 04 '18 at 07:34
  • @n.m. your suggestion is to do 'if (pthread_mutex_lock(&m_writer)) { exit(1)}' ? – Matan Jan 04 '18 at 07:42
  • Call perror or equivalent when you get an unexpected error. Then you can exit the program or recover. – n. m. could be an AI Jan 04 '18 at 07:44
  • note that printf is thread safe. – Stargateur Jan 04 '18 at 07:45

1 Answers1

4

strace shows results of system calls. Pthread functions in Linux are not system calls, they are libc functions implemented on top of (potentilally non-trivial) system calls. You are not interested in what internal system calls return. A single successfull call to ptread_mutex_lock may and sometimes does entail several failing syscalls.

In particular, pthread_mutex_lock cannot possibly result in EAGAIN in this program because there are no attempts to lock the mutex recursively, and the default mutex is not recursive in Linux anyway. The FUTEX_WAIT_PRIVATE syscall that pthread_mutex_lock uses internally can and will result in EAGAIN. This is of no interest whatsoever to the application programmer.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Worth adding that `futex` syscall is failing here because locking has failed, but thread observed that mutex was unlocked after syscall but before it was able to sleep. –  Jan 04 '18 at 13:51