For loop not terminating once condition is met using pthread

Viewed 75

I was writing a piece of multithreaded code when I found that a for loop was not terminating. The starting code was approximately like this:

for(int i = V-1-tid; i >= 0; i-=NTHREADS){
  */ stuff */
}

V and NTHREADS are constants and tid is the thread id passed using pthread_create.

I then removed everything from the loop and wrote something like this to make sure nothing was interfering with i:

for(int i = 0; i<100; i++){
  std::cout<<i<<"<100? "<<(i<100)<<std::endl;
}

This still does not stop.

I spawn the threads using a simple:

for(int i = 0; i < NTHREADS; i++){
  pthread_create(&(threads[i]), NULL, foo, &(parameters[i]));
}

I tried declaring i as volatile, but this changed nothing. If I compile with -O0 then the loop stops correctly, but everything above -O0 has the same problem.

I am using gcc 9.4.0, more specifically g++-9 (Homebrew GCC 9.4.0) 9.4.0, and the flags I am using are:

-O3 -mavx -mavx2 -mfma -std=c++11 -march=native -fno-rtti -lquadmath -lpthread -g

I am currently looking through the assembly output from gcc to see what's happening, but understanding optimized x86 is a bit of a pain.

Am I missing something obvious? Is there anything I can try?

Edit: Added example.

EXAMPLE CODE:

#include <iostream>
#include <pthread.h>
#define NTHREADS 1

void *foo(void *args){
  for(int i = 0; i < 100; i++){
    std::cout<<i<<std::endl;
  }
}

int main(){
  pthread_t threads[NTHREADS];

  for(int i = 0; i < NTHREADS; i++){
    pthread_create(&(threads[i]), NULL, foo, NULL);
  }

  for(int i = 0; i < NTHREADS; i++){
    pthread_join(threads[i], NULL);
  }
}

The output I am getting can be seen here: godbolt.org/z/Mfjrj6Khr

1 Answers

The code has undefined behavior - a function has return type void * but does not return anything. The compiler gets confused and generates an endless loop.

Make sure to enable and listen to compiler warnings, they tell you that:

1.cpp: In function ‘void* foo(void*)’:
1.cpp:7:1: warning: no return statement in function returning non-void [-Wreturn-type]
    7 | }
      | ^

The shortest MCVE I was able to come up with that illustrates the point:

#include <cstdio>
void* foo() {
  for(int i = 0; i < 100; i++){
    putchar(i);
  }
}
int main() {
    foo();
}

that when compiled with -O3 on godbolt with g++11.1 does:

foo():
        push    rbx
        xor     ebx, ebx
.L2:
        mov     rsi, QWORD PTR stdout[rip]
        mov     edi, ebx
        add     ebx, 1
        call    putc
        jmp     .L2            # Just an endless loop.
main:
        sub     rsp, 8
        call    foo()
Related