LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Threading program with various counters (https://www.linuxquestions.org/questions/linux-newbie-8/threading-program-with-various-counters-4175483073/)

pratham29 11-01-2013 03:54 PM

Threading program with various counters
 
Study the example program in the attached file. This program creates a new thread. Both the main thread and the new thread then increment the variable counter 20 times. But the program itself produces some unexpected results.

1. Compile and run the program on a Linux system. Find out what results it produces and explain the results.
Compile as follows:
$ gcc thread2.c -o thread2 -lpthread

Run using the following command
$ ./thread2

2. Modify the program so that the variable counter has a value of 40 when the program ends.
Hint: use synchronization primitives.

Please submit a zip file labelled as Assignment4_Yourname.zip. It should include a PDF file with explanation of the results and a C source file with the modified program.


Clarification: One some systems, you might not see the unexpected result right away. In that case, run the program several times and see if you get any unexpected results. If you still don't see anything, insert some sleep statements into both the thread functions and manually study the code and point out what's wrong with the code.

____________________________________________________________________________________________________ ______________________

Code:

/* Save this program as thread2.c */
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int counter=0;
 void *thread_function(void *arg) {
  int i,j;
  for ( i=0; i<20; i++ ) {
    j=counter;
    j=j+1;
    printf(".");
    fflush(stdout);

    counter=j;
}
  return NULL;
}
int main(void) {
  pthread_t mythread;
  int i;
  if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {
    printf("error creating thread.");
    abort();
}
  for ( i=0; i<20; i++) {
    counter=counter+1;
    printf("o");
    fflush(stdout);
 
}
  if ( pthread_join ( mythread, NULL ) ) {
    printf("error joining thread.");
    abort();
  }
  printf("\ncounter equals %d\n",counter);
  exit(0);
}

OUTPUT:
guest@ubuntu:~$ cd Desktop/
guest@ubuntu:~/Desktop$ gcc thread2.c -o thread2 -lpthread
guest@ubuntu:~/Desktop$ ./thread2
oooooooooooooooooooo....................
counter equals 40
guest@ubuntu:~/Desktop$


I get the following output, kindly help me with the question 2 part.

Thanks in advance.
Regards,
Pratham

Habitual 11-01-2013 03:57 PM

Do not post homework assignments verbatim. We're happy to assist if you have specific questions or have hit a stumbling point, however. Let us know what you've already tried and what references you have used (including class notes, books, and searches) and we'll do our best to help. Keep in mind that your instructor might also be an LQ member.

Teachers hang out here too. :)

jpollard 11-01-2013 04:23 PM

Oh, it is sufficiently specific.

counter is a global variable - and without synchronized access, each thread MAY retrive the value as the value gets updated... at random times. The actions on the variable counter MAY get updated before the main thread increments it.

Because it isn't synchronized, the end result depends on the system.

On my system, I get:
Code:

$./a.out
oooooooooooooooo.o...................ooo
counter equals 24
$./a.out
ooooo........ooooooooooooooo............
counter equals 21
$ !!
./a.out
ooooo.ooooooooooooooo...................
counter equals 21
$

But then, I have multiple processors.

What happens is that the second thread gets initiated... but due to scheduling delays the original thread continues running - producing a string "o"s... By the time the second thread gets started (it has to migrate to a second processor), several "ooo..." are output BEFORE the first "." from the second thread. In the meantime, there is also buffer packing going on (which delays things), and packs a number of bytes together. In fact, this may be the overriding effect putting so many "o"s together.

The reason the counter gets the "wrong" output is again due to the scheduling.
The second thread is going to set the value "20". The primary thread is just incrementing counter. The earlier the child gets to run, the higher the count will be.

If the main thread runs first, the value will be closest to "20". If the second thread runs first the value will be closer to 40. But note, "counter" is itself NOT INITIALIZED, and can be a source of additional problems.

And the reason the output string is as it is, has to do with the runtime buffers... you have no synchronization with them so whatever you get is up to how things get scheduled... and the timing of the buffer outputs...

It is a "good" example of how NOT to approach threading.

pratham29 11-02-2013 03:54 PM

I am still getting the same output counter= 40 for every compilation , can you explain about the variable outputs you received

jpollard 11-03-2013 02:17 AM

I did. It is relatively random, depending on how process scheduling (and how quickly) is done. It also depends on general system load.

It sounds very much like you have a single CPU.

coopster 11-03-2013 07:05 AM

Hi.

So p~29 has this hwork problem but what's really happening here?
I guess the counter represents some real world process, and he basically has two threads that need to update their "outputs" based on accessing that first process? Or I suppose the first thread instance could be whatever process, and the second thread executes before or during the first? So is the point to get both threads to count to 40, or count to 40 simultaneously, or one not to complete the count until the other catches up (completes)?

jpollard, thanks. Q: Would you (he) then put a lock or some other control on his code before first count, or is that only if a person is trying to make them put out a '.' or an 0 syncronously?

jpollard 11-03-2013 09:32 AM

In neither case would work...

What you are seeing is the problem with multi-threading at the fine grain level of an instruction - 10 nanoseconds or so.

The counter doesn't represent squat. It is just demonstrating that synchronization is not reliable at that level. You can put locks on the counter variable... Won't fix much
but it would get more reliable.

The major problem is the coarse grained process scheduling done relative to the fine grained acts of counting. Which ever process starts first gets the most access to the counter... When it finishes the other gets access.

And the same problem applies to the use of the file pointer used for output.


All times are GMT -5. The time now is 12:36 PM.