0

I want to print the odd numbers in main thread and even numbers in new thread. I tried writing a program but it was only printing odd numbers not the even numbers. I tried searching for clues to find what is wrong but didn't find any.

This is my code.

#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#define MAX 1000

int count = 0;

void print_odd_numbers();
void *print_even_numbers();

int main() {
    pthread_t t;
    int iret;
    iret = pthread_create(&t, NULL, print_even_numbers, NULL);
    print_odd_numbers();        
    pthread_join(t, NULL);
    return 0;
}

void print_odd_numbers() {
    while(count <= MAX) {
        if(count % 2 == 1) {
            printf("%d\n", count);
        }
        count++;
    }
}

void *print_even_numbers() {
    while(count <= MAX) {
        if(count % 2 == 0) {
            printf("%d\n", count);
        }
        count++;
    }
    pthread_exit(NULL);
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Priyanka Naik
  • 344
  • 6
  • 13
  • 2
    Each thread needs its own 'count' variable. Don't use globals! – Martin James Sep 02 '17 at 19:40
  • @MartinJames I have seen many programs wherein they keep the count global. Actually the two threads should run in parallel, so the count they refer should be same. As per my knowledge. Please help if I am wrong. – Priyanka Naik Sep 02 '17 at 19:55
  • 1
    @Priyanka Naik No, this is incorrect. The reason has to do with CPU cache coherence. Unless you are using specific operations designed to atomically increment a shared value in a cache-coherent fashion, you can have two CPUs (or cores) each iterating over their own copy of the variable in the cache and then they both write their copy back at some point. Also, the compiler doesn't have to re-read the value from memory, but that's another story. – Daniel Santos Sep 02 '17 at 20:09
  • 1
    @PriyankaNaik ' I have seen many programs wherein they keep the count global.' -unfortunately, given the umm.. 'less than stellar' quality of may 'Intro to threads' sites/books, I'm not really surprised:( – Martin James Sep 02 '17 at 20:33
  • @Martin James lol!! – Daniel Santos Sep 02 '17 at 20:40

2 Answers2

1

The fact that both print_odd_numbers and print_even_numbers increment count even if they don't print anything is the source of much of the trouble here.

All the increments to count will be made in print_odd_numbers, and count will be set to MAX before print_even_numbers gets started.

Making count local to the functions could help, or being much more careful in how count is incremented is another way - if you retain its global nature, then you ought to consider using atomic increments.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

If you do not let the compiler know that your count is used by multiple threads, then it can completely rearrange your code. For example, the compiler probably changed print_odd_numbers to something more like

void print_odd_numbers() {
    if (count <= MAX) {
        if(count % 2 == 1) {
            printf("%d\n", count);
        }
        count++;
    }
    while(count <= MAX) {
        printf("%d\n", count);
        count += 2;
    }
}

Furthermore, each CPU or core will be working with it's own copy of count because we have all of these awesome CPU caches that speed things up so much. Unless you somehow let your compiler know that this memory location is used by other threads, then each thread (if running on it's own core) will just use their own copy and then at some point write that value back to main memory.

You need to use an atomic increment instruction or guard your global with a mutex, critical section, semaphore, etc.. When you use semaphores, mutexes, etc. the compiler automatically generates a LOCK instruction (on x86, or similar for other archs) which forces the CPU to manage memory in it's cache in a coherent fashion across CPUs and cores.

pthreads: If I increment a global from two different threads, can there be sync issues?

Daniel Santos
  • 3,098
  • 26
  • 25