-1

A multi-process and multi-threaded implementation of three linked lists with 1000000 nodes using merge sort was implemented. I compared the real-time of the implemented program, but the multi-thread method is slower. Why is that?

main method in process.c

    /* Insert nodes */
    Node* tmp = NULL;   
    int num;    
    for( int i = 0; i < MAX; i++ )
    {
        fscanf(fread,"%d",&num);    
        tmp = createNode(num , i ); 
        insertNode( &list1.head, &list1.tail, tmp );
        tmp = createNode(num , i ); 
        insertNode( &list2.head, &list2.tail, tmp );    
        tmp = createNode(num , i );
        insertNode( &list3.head, &list3.tail, tmp );    
        tmp = createNode(num , i ); 
    }
    free( tmp );    
    fclose(fread);  

    if ((t1 = times(&mytms)) == -1) {
        perror("times 1");
        exit(1);
    }

    pid1= fork();   
    if(pid1==0){
        mergeSort( &list1.head );   
        file_output(&list1);    
        freeAll( list1.head );
        exit(1);    
    }
    pid2= fork();   
    if(pid2==0){
        mergeSort( &list2.head );   
        file_output(&list2);    
        freeAll( list2.head );  
        exit(2);    
    }
    pid3 = fork();
    if(pid3==0){
        mergeSort( &list3.head );   
        file_output(&list3);    
        freeAll( list3.head );  
        exit(3);    
    }

    wait(&status);  
    wait(&status);
    wait(&status);

    if ((t2 = times(&mytms)) == -1) {   
        perror("times 2");
        exit(1);
    }

    printf("Real time : %.5f sec\n", (double)(t2 - t1) / CLK_TCK);
    printf("User time : %.5f sec\n", (double)mytms.tms_utime / CLK_TCK);
    printf("System time : %.5f sec\n", (double)mytms.tms_stime / CLK_TCK);

Result real-time : 1.65

main in thread.c

   /* Insert nodes */
   Node* tmp = NULL;   
   int num;           

   for( int i = 0; i < MAX; i++ )
   {
      fscanf(fread,"%d",&num); 
      tmp = createNode(num , i ); 
      insertNode( &list1.head, &list1.tail, tmp );  
      tmp = createNode(num , i );  
      insertNode( &list2.head, &list2.tail, tmp );  
      tmp = createNode(num , i );  
      insertNode( &list3.head, &list3.tail, tmp );  
   }

   free( tmp );
   fclose(fread);  

   if ((t1 = times(&mytms)) == -1) {
        perror("times 1");
        exit(1);
   }

   pthread_create( &t_id1, NULL, thread_func, &list1 );
   pthread_create( &t_id2, NULL, thread_func, &list2 );
   pthread_create( &t_id3, NULL, thread_func, &list3 );

   pthread_join( t_id1, (void*)&status );
   pthread_join( t_id2, (void*)&status );
   pthread_join( t_id3, (void*)&status );

   if ((t2 = times(&mytms)) == -1) {
        perror("times 2");
      exit(1);
   }

   printf("Real time : %.5f sec\n", (double)(t2 - t1) / CLK_TCK);
   printf("User time : %.5f sec\n", (double)mytms.tms_utime / CLK_TCK);  
   printf("System time : %.5f sec\n", (double)mytms.tms_stime / CLK_TCK);  

result real-time 2.27

gowoo
  • 11
  • 3
  • 5
    It's unclear which parts of this code belong to which functions. Please create a proper [mcve] that others can copy-paste and try out themselves – UnholySheep Jun 10 '20 at 16:41
  • Threads and child processes merge sort random 1,000,000 nodes, then fwrite and free them. – gowoo Jun 10 '20 at 16:47
  • 2
    You could probably write a simpler example to prove/demonstrate the point. Something with simple calculations rather than linked lists and sorting. – Eugene Sh. Jun 10 '20 at 16:48
  • I suspect that the processes that you create via `fork` are still running when you output the results from the main process. – 1201ProgramAlarm Jun 10 '20 at 17:02
  • Isn't the parent process blocked because it waits? – gowoo Jun 10 '20 at 17:06
  • 1
    You have 3 consecutive calls to `wait(&status);`. How would the 2nd call differ from the 1st? What is `status`? At best that will wait for the same thing 3 times, resulting in only 1 wait. – 1201ProgramAlarm Jun 10 '20 at 17:08
  • I checked the status value, and it was output differently as 1,2,3. Didn't exit() return? If yes, the three child processes have ended – gowoo Jun 10 '20 at 17:12
  • @1201ProgramAlarm, `wait(&status)` waits for _any_ child process to "change state" (usually, to terminate.) The `status` argument effectively is an `OUT` parameter through which the `wait()` call returns the exit status of the child that terminated. If a program forks three times, and then calls `wait()` three times, then it should be safe to assume\* that all three children have terminated after the third `wait()` returns. – Solomon Slow Jun 10 '20 at 18:20
  • \* It's never _really_ safe to assume... There are other events that could cause `wait()` to return, but probably won't happen in this simple example. – Solomon Slow Jun 10 '20 at 18:21

1 Answers1

-1

Why is multithreading slower?

It is processor specific and tied to the number of cores, the organization of CPU caches, their cache coherence, your RAM. See also tests and benchmarks on https://www.phoronix.com/ ; it won't be the same on Intel Core i7 10700K and on AMD Ryzen 9 3900X (whose price are close).

It is also both compiler and optimization specific. Read the Dragon book and a good book on Computer Architecture.

It also depends upon your particular operating system and your particular C standard library (e.g. GNU glibc is not the same as musl-libc), and glibc 2.31 could have different performance than glibc 2.30 on the same computer. Read Advanced Linux Programming, pthreads(7), nptl(7), numa(7), time(7), madvise(2), syscalls(2)

Did you try on a recent Linux with a recent GCC 10 invoked as gcc -Wall -O3 -mtune=native at least?

You could use proc(5) then hwinfo on Linux to query your hardware.

You might be interested in OpenCL, OpenMP, or OpenACC, and you should read about optimization options of your particular C compiler. For recent GCC, see this. You could even customize your recent GCC with your GCC plugins to improve optimizations, and you could try a recent Clang or icc compiler.

See also the MILEPOST GCC project and the CTuning one. Read also this draft report. Attend ACM SIGPLAN and SIGOPS conferences. Contact computer science academics near you.

you probably could get a PhD while understanding the answer to your question.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547