title: Many invalid symbol indices and undefined reference to main
body: <p>I have two programs I created. One is myThreads.c, and the other is myThreads_test.c, all in the same directory. Within that directory, I also have libslack.c which I use for its list capabilities. Finaly, I do have a myThreads.h</p>
  
  <p>I try to compile using:</p>
  
  <pre><code>gcc -o  myThreads_test.c myThreads.c -DHAVE_PTHREAD_RWLOCK=1 -lslack  -lrt
  </code></pre>
  
  <p>or</p>
  
  <pre><code>gcc -o  myThreads.c myThreads_test.c -DHAVE_PTHREAD_RWLOCK=1 -lslack  -lrt
  </code></pre>
  
  <p>and get the following errors:</p>
  
  <pre><code>   /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 0 has      invalid symbol index 11
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 12
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 4 has invalid symbol index 11
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 5 has invalid symbol index 13
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 6 has invalid symbol index 13
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 7 has invalid symbol index 13
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 8 has invalid symbol index 2
     /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 9 has invalid symbol index 2
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 10 has invalid symbol index 12
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 11 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 12 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 13 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 14 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 15 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 16 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 17 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 13
    /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 13
   /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 20 has invalid symbol index 13
  /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 21 has invalid symbol index 13
  /usr/bin/ld: /usr/lib/debug/usr/lib/i386-linux-gnu/crt1.o(.debug_info): relocation 22 has invalid symbol index 21
  /usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
  (.text+0x18): undefined reference to `main'
   collect2: ld returned 1 exit status
  </code></pre>
  
  <p>Which is weird because it seems the linker is throwing the errors not the compiler. In addition to that, depending on what order the c programs are in the above compilation commands, either myThreads.c gets deleted or myThreads_test.c gets deleted. I've neve seen that before.</p>
  
  <p>So I tried compiling with the different lines above. I have a feeling it has to do with the way I'm compiling though.</p>
  
  <p>Here is myThreads.c</p>
  
  <pre><code>/*!
   @file myThreads.c
   An implementation of a package for creating, using and
   managing preemptive threads in linux. 
  */
  
  // Assignment 1
  // Author: Georges Krinker
  // Student #: 260369844
  // Course: ECSE 427 (OS)
  // Note: This file has been commented using doxygen style. 
  //       The API can be found at gkrinker.com/locker/OS/pa1
  //       Refer to doxygen.org for more info
  
   /********************************************//**
   *  Includes
   ***********************************************/
  
  
  #include &lt;signal.h&gt;
  #include &lt;sys/time.h&gt;
  #include &lt;time.h&gt;
  #include &lt;stdio.h&gt;      
  #include &lt;stdlib.h&gt;     
  #include &lt;math.h&gt;
  #include "myThreads.h"
  
  /********************************************//**
   *  Defines
   ***********************************************/
  
  #define MAX_NUMBER_OF_THREADS 20    ///&lt; Limit on number of threads that can be created
  #define MAX_NUMBER_OF_SEMAPHORES 5  ///&lt; Limit on number of semaphores that can be created
  #define DEFAULT_QUANTUM 250         ///&lt; Default value for quantum if non is specified
  
  /**
   * Thread States
   */
  #define BLOCKED 0
  #define RUNNABLE 1
  #define EXIT 2
  #define RUNNING 3
  #define NOTHREAD -1
  
   /**
    * Error Handling
    */
  
  #define handle_error(msg) \
      do { perror(msg); exit(EXIT_FAILURE); } while(0)
  
  /********************************************//**
   *  Global Variables
   ***********************************************/
  
  static ucontext_t mainContext;                          ///&lt; Main context for initial thread
  static int quantum;                                     ///&lt; Quantum
  static int threads_completed;                           ///&lt; 1 if all threads finished execution, ie EXIT state
  static int currentThread;                               ///&lt; ID of currently running thread
  static long dispatcherCount;                            ///&lt; Number of times the dispatcher has been called. 
  
  static List *runQueue;                                  ///&lt; Thread Run Queue. Holds indices to the tcb table
  static mythread_control_block table[MAX_NUMBER_OF_THREADS];                     ///&lt; Holds thread control blocks
  static semaphore semaphores[MAX_NUMBER_OF_SEMAPHORES];      ///&lt; Holds semaphores
  static int tableIndex;                                  ///&lt; Holds the next free table index in the table
  static int semaphoresIndex;                             ///&lt; Holds the enxt free semaphore index in the table
  
  static sigset_t block_alarm;                            ///&lt; The signal set that will be blocked
  
  /********************************************//**
   *  Functions
   ***********************************************/
  
   /**
   * This function initializes all the global data structures for the thread system. 
   *
   * Creates a new Run Queue and initilaizes the indices for both the 
   * TCB table and Semaphore table to 0. It then initializes the TCB
   * and semaphore table. Finally, [TO BE COMPLETED]
   */
   int mythread_init(){
      runQueue = list_create(NULL);
      tableIndex=0;
      semaphoresIndex=0;
      currentThread = -1; //No threads have been created yet.
      int i;
      quantum = DEFAULT_QUANTUM;
      threads_completed = 0;
  
      //Set all Thread Statuses to 'No Thread' in the TCB table
      for(i=0;i&lt;MAX_NUMBER_OF_THREADS;i++){
          table[i].status=NOTHREAD;
      }
      // Set all semaphores to inactive
      int j;
      for(j=0; j&lt;MAX_NUMBER_OF_SEMAPHORES; j++)
          semaphores[j].active = 0;
  
      sigemptyset (&amp;block_alarm);
      sigaddset (&amp;block_alarm, SIGALRM);
  }
  
  /**
   * This function creates a new thread.
   *
   * The function is responsible for allocating the stack and setting
   * up the user context appropriately. The newly created thread
   * starts running the threadfunc function when it starts. The
   * threadname is stored in the TCB and is printed for info 
   * purposes The newly created thread is in the RUNNABLE
   * state when inserted into the system. It is added to the run queue.
   * @return the ID of the newly created thread
   * @param *threadfunc() function to be called on context switch
   * @param stacksize size of stack to be allocated to
   */
  int mythread_create(char *threadName, void (*threadfunc)(), int stacksize){
  
      // Handle the error if any
      if (getcontext(&amp;table[tableIndex].context) == -1)
        handle_error("ERROR IN GETCONTEXT!");
  
      // Allocate a stack for the new thread and set it's return context
      table[tableIndex].context.uc_stack.ss_size = stacksize;             //Set stack size
      table[tableIndex].context.uc_stack.ss_sp = malloc(stacksize);       // allocate that space
      table[tableIndex].context.uc_link = &amp;mainContext;                   // set the return context as the main Context
  
      // Modify the context and fill out the thread info on the TCB table
      makecontext(&amp;table[tableIndex].context, threadfunc, 0);             // set the function call and 0 arguments
      table[tableIndex].name = threadName;                                // set the thread name
      table[tableIndex].threadID = tableIndex;                            // set the thread ID
      table[tableIndex].status = RUNNABLE;                                // set the thread as RUNNABLE
      runQueue = list_append_int(runQueue, tableIndex);                   // add it to the run queue
  
      tableIndex++;                                                       //point to the next free slot
  
      return tableIndex-1;                                                // returns ID of thread
  }
  /**
   * This function is called at the end of the function that was invoked
   * by the thread. 
   *
   * The function firstly masks signals, sets the status of that
   * thread to 'EXIT' and then unblocks signals before returning.
   */
  void mythread_exit(){ 
      sigprocmask (SIG_BLOCK, &amp;block_alarm, NULL);
      table[currentThread].status=EXIT;
      sigprocmask (SIG_UNBLOCK, &amp;block_alarm, NULL);
  }
  /**
   * Sets the quantum for the round robin (RR) scheduler.
   *
   * @param quantum_size quantum size in us
   */
  void set_quantum_size(int quantum_size){
      quantum = quantum_size;
  }
  
  /**
   * Schedules threads in a Round Robin fashion.
   *
   * The function starts by checking if there are no more threads to run.
   * If that is the case, it sets threads_completed to 1 so that 
   * run_threads() will terminate and resume to the mainContext.
   * If there are still runnable threads, the dispatcher switches threads
   * by swapping context, and putting the expired thread at the end of the
   * run queue. Finally, if there is only one runnable thread, that thread
   * is allowed to run for one more quantum.
   */
  void dispatcher(){  
      dispatcherCount++;
      //if there are no more threads to run, and the current thread is done, set
      // threads_completed to 1
      if(list_empty(runQueue) &amp;&amp; table[currentThread].status==EXIT){
              threads_completed=1;
              swapcontext(&amp;table[currentThread].context, &amp;mainContext);
          }
          //else switch to the next thread
      else if(!list_empty(runQueue)){ 
          int nextThread = list_shift_int(runQueue);                          
          int tempCurrent = currentThread; 
          currentThread = nextThread;
          // if the current thread (which is yielding to the next runnable thread) is runnable, queue it 
          //back in the runqueue
          if(table[tempCurrent].status != EXIT &amp;&amp; table[tempCurrent].status!=BLOCKED){
                  runQueue = list_append_int(runQueue, tempCurrent);
                  table[tempCurrent].status = RUNNABLE;
          }
          table[nextThread].status = RUNNING; //set the the enxt thread to run
          sigprocmask (SIG_BLOCK, &amp;block_alarm, NULL); //stop the dispatcher from being called while updating timing
          clock_gettime(CLOCK_REALTIME, &amp;table[tempCurrent].stopTime); //record stop time
          table[tempCurrent].elapsedTime += (double) (table[tempCurrent].stopTime.tv_nsec - table[tempCurrent].startTime.tv_nsec); //update elapsed time
          clock_gettime(CLOCK_REALTIME, &amp;table[currentThread].startTime);//record start timer of new thread
                  sigprocmask (SIG_UNBLOCK, &amp;block_alarm, NULL);
          //switch context
          swapcontext(&amp;table[tempCurrent].context, &amp;table[nextThread].context); 
      }
      else{
          //Keep the only thread that's runnable for 1 more quantum (do nothing!)
      }
  }
  
  /**
   * The runthreads() switches control from the main thread to one of the threads in the runqueue.
   *
   * The function starts by defining a signal timer that triggers every
   * quantum usecs and calls the dispatcher. The function then starts the
   * first thread by doing a context switch.
   */
  void runthreads(){
      //Set up the signal alarm to call dispatcher() every quantum interval
      struct itimerval tval;
      sigset(SIGALRM, dispatcher);
      tval.it_interval.tv_sec = 0;
      tval.it_interval.tv_usec = quantum;
      tval.it_value.tv_sec = 0;
      tval.it_value.tv_usec = quantum;
      setitimer(ITIMER_REAL, &amp;tval, 0);
  
      // If there is nothing to run, throw an error!
      if(list_empty(runQueue)){
          handle_error("In runthreads: RUN QUEUE IS EMPTY!");
      }
      else{
          int nextThread = list_shift_int(runQueue);                          //find the next thread to run
          currentThread = nextThread;                                         //make it the current thread
          table[currentThread].status = RUNNING;                              //set it to running
          sigprocmask (SIG_BLOCK, &amp;block_alarm, NULL);                        //stop signal from interrupting the timing calculations
          clock_gettime(CLOCK_REALTIME, &amp;table[currentThread].startTime);     //record start time of the new current thread
          sigprocmask (SIG_UNBLOCK, &amp;block_alarm, NULL);
          swapcontext(&amp;mainContext, &amp;table[nextThread].context);              //swap context
      }
      //only stop when there are no more threads to run!  
      while(!threads_completed);
  }
  /**
   * This function creates a semaphore and sets its initial value to the given parameter. 
   *
   * @param value initial semaphore value
   */
  int create_semaphore(int value){
      // handle error as usual if value is less than 0
      if(value &lt; 0)
             handle_error("semaphore initialization failed - value less than 0.");
      else{
          semaphores[semaphoresIndex].initialValue = value;                               //set initial value to value
          semaphores[semaphoresIndex].value = semaphores[semaphoresIndex].initialValue;   //set value
          semaphores[semaphoresIndex].active = 1;                                         // make it ative now
          semaphores[semaphoresIndex].waitingThreads = list_create(NULL);                 //create a waitingThreads list for it
      }
      semaphoresIndex++;
  
      return semaphoresIndex-1; //return ID
  }
  
  /**
   * Calls wait() on a Semaphore
   *
   * When a thread calls this function, the value of the semaphore is decremented.
   * If the value goes below 0, the thread is put into a WAIT state. That means
   * calling thread is taken out of the runqueue if the value of the semaphore
   * goes below 0.
   * @param semaphore index of semaphore to be manipulated in the table 
   *
   */
  void semaphore_wait(int semaphore){ 
      long oldDispatcherCount=dispatcherCount;
      //if trying to access a semaphore that doesn't show or is inactive handle it
      if(semaphore &gt; semaphoresIndex || semaphores[semaphore].active==0)
          handle_error("Wrong semaphore index in wait()");
  
      sigprocmask (SIG_BLOCK, &amp;block_alarm, NULL);                                //mask signals for changing semaphore value (indivisibility)
      if(--semaphores[semaphore].value&lt;0){                                        // if value &lt; 0, add thread to waiting queue
          list_append_int(semaphores[semaphore].waitingThreads, currentThread);   
          table[currentThread].status = BLOCKED;                                  // change the status of the semaphore to BLOCKED
      }
      sigprocmask (SIG_UNBLOCK, &amp;block_alarm, NULL);                              // Re-nable signals
      while(dispatcherCount == oldDispatcherCount);                               //wait for the scheduler to switch threads (could be made more efficient)
  }
  /**
   * Calls signal() on a Semaphore
   *
   * When a thread calls this function the value of the semaphore is incremented.
   * If the value is not greater than 0, then we should at least have one thread
   * waiting on it. The thread at the top of the wait queue associated with the
   * semaphore is dequeued from the wait queue and queued in the run queue. The
   * thread state is then set to RUNNABLE.
   * @param semaphore index of semaphore to be manipulated in the table 
   * 
   */
  void semaphore_signal(int semaphore){
      //if trying to access a semaphore that doesn't show or is inactive handle it
      if(semaphore &gt; semaphoresIndex || semaphores[semaphore].active &lt;0)
          handle_error("Wrong semaphore index in signal()");
  
      if(++semaphores[semaphore].value&lt;=0){                                       // if there are threads waiting...
          if(list_empty(semaphores[semaphore].waitingThreads))                    //contradiction! No thread waiting? Error!
              handle_error("in Semaphore signal: there should be at least one waiting thread in semaphore");
          //Dequeue a waiting thread and set it to RUNNABLE. Then add it to the run queue
          int readyThread = list_shift_int(semaphores[semaphore].waitingThreads);
          table[readyThread].status = RUNNABLE;
          list_append_int(runQueue, readyThread);
      }
  }
  /**
   * Destroys a semaphore.
   *
   * A call to this function while threads are waiting on the semaphore should fail.
   * That is the removal process should fail with an appropriate error message. 
   * If there are no threads waiting, this function will proceed with the removal
   * after checking whether the current value is the same as the initial value of 
   * the semaphore.  If the values are different, then a warning message is 
   * printed before the semaphore is destroyed.
   * @param semaphore index of semaphore to be manipulated in the table 
   * 
   */
  void destroy_semaphore(int semaphore){
      //if trying to access a semaphore that doesn't show or is inactive handle it
      if(semaphore &gt; semaphoresIndex || semaphores[semaphore].active ==0)
          handle_error("Wrong semaphore index in destroy()");
      //initil and final value check
      if(semaphores[semaphore].value != semaphores[semaphore].initialValue){
          puts("\nWARNING: Destroying a semaphore with different initial and final values!\n");
      }
      //check that there are no threads waiting on this baby
      if(!list_empty(semaphores[semaphore].waitingThreads)){
          printf("Semaphore %i was not destroyed since one or more threads are waiting on it..\n",semaphore);
      }
      //destroy it by setting it to inactive!
      else{
      semaphores[semaphore].active = 0;
      }
  }
  /**
   * Prints the state of all threads that are maintained by the library at
   * any given time.
   *
   * For each thread, it prints the following information in a tabular 
   * form: thread name, thread state (print as a string RUNNING, BLOCKED, 
   * EXIT, etc), and amount of time run on CPU.
   * 
   */
  void my_threads_state(){
      int i;
      char* string;
      for(i=0; i&lt;MAX_NUMBER_OF_THREADS; i++){
          if(table[i].status != -1){
              switch(table[i].status){
                  case 0: string = "BLOCKED"; break;
                  case 1: string = "RUNNABLE"; break;
                  case 3: string = "RUNNING"; break;
                  case 2: string = "EXIT"; break;
              }
              printf("thread name: %s with ID number: %i is in state: %s and has run for %fms.\n",
               table[i].name, i, string, table[i].elapsedTime/1000000);
          }
      }
  }
  </code></pre>
  
  <p>Here is myThreads.h</p>
  
  <pre><code>/*!
   @file myThreads.h
   An implementation of a package for creating, using and
   managing preemptive threads in linux. 
  */
  
  // Multiple-include guard
  #ifndef __myThreads_H_
  #define __myThreads_H_
  
   #include &lt;ucontext.h&gt;
   #include &lt;slack/std.h&gt;  
   #include &lt;slack/list.h&gt;
  
  /********************************************//**
   *  Structures
   ***********************************************/
  
   /*! \brief Structure that represents the thread control block (TCB). 
   */ 
  
   typedef struct _mythread_control_block {
      ucontext_t context;
      char *name;
      int threadID; //Between 0-# of Threads
      int status; // Any of the above defines
      struct timespec startTime;  //when it was created
      struct timespec stopTime;   // when it was stopped
      double elapsedTime; //start-stop in ns
  
   }mythread_control_block;
  
   typedef struct _mythread_semaphore{
      int value; 
      int initialValue;
      int active;
      List *waitingThreads; // holds indices to the semaphores table
  }semaphore;
  
  /********************************************//**
   *  Functions
   ***********************************************/
  
   /**
   * This function initializes all the global data structures for the thread system. 
   *
   * Creates a new Run Queue and initilaizes the indices for both the 
   * TCB table and Semaphore table to 0. It then initializes the TCB
   * and semaphore table. Finally, [TO BE COMPLETED]
   */
   int init_my_threads();
  /**
   * This function creates a new thread.
   *
   * The function is responsible for allocating the stack and setting
   * up the user context appropriately. The newly created thread
   * starts running the threadfunc function when it starts. The
   * threadname is stored in the TCB and is printed for info 
   * purposes The newly created thread is in the RUNNABLE
   * state when inserted into the system. It is added to the run queue.
   * @return the ID of the newly created thread
   * @param *threadfunc() function to be called on context switch
   * @param stacksize size of stack to be allocated to
   */
  int mythread_create(char *threadName, void (*threadfunc)(), int stacksize);
  
  /**
   * This function is called at the end of the function that was invoked
   * by the thread. 
   *
   * The function firstly masks signals, sets the status of that
   * thread to 'EXIT' and then unblocks signals before returning.
   */
  void mythread_exit();
  
  /**
   * Sets the quantum for the round robin (RR) scheduler.
   *
   * @param quantum_size quantum size in us
   */
  void set_quantum_size(int quantum_size);
  
  /**
   * Schedules threads in a Round Robin fashion.
   *
   * The function starts by checking if there are no more threads to run.
   * If that is the case, it sets threads_completed to 1 so that 
   * run_threads() will terminate and resume to the mainContext.
   * If there are still runnable threads, the dispatcher switches threads
   * by swapping context, and putting the expired thread at the end of the
   * run queue. Finally, if there is only one runnable thread, that thread
   * is allowed to run for one more quantum.
   */
  void dispatcher();
  
  /**
   * The runthreads() switches control from the main thread to one of the threads in the runqueue.
   *
   * The function starts by defining a signal timer that triggers every
   * quantum usecs and calls the dispatcher. The function then starts the
   * first thread by doing a context switch.
   */
  void runthreads();
  
  /**
   * This function creates a semaphore and sets its initial value to the given parameter. 
   *
   * @param value initial semaphore value
   */
   int create_semaphore(int value);
  
   /**
   * Calls wait() on a Semaphore
   *
   * When a thread calls this function, the value of the semaphore is decremented.
   * If the value goes below 0, the thread is put into a WAIT state. That means
   * calling thread is taken out of the runqueue if the value of the semaphore
   * goes below 0.
   * @param semaphore index of semaphore to be manipulated in the table 
   *
   */
  void semaphore_wait(int semaphore);
  
  /**
   * Calls signal() on a Semaphore
   *
   * When a thread calls this function the value of the semaphore is incremented.
   * If the value is not greater than 0, then we should at least have one thread
   * waiting on it. The thread at the top of the wait queue associated with the
   * semaphore is dequeued from the wait queue and queued in the run queue. The
   * thread state is then set to RUNNABLE.
   * @param semaphore index of semaphore to be manipulated in the table 
   * 
   */
   void semaphore_signal(int semaphore);
  
  /**
   * Prints the state of all threads that are maintained by the library at
   * any given time.
   *
   * For each thread, it prints the following information in a tabular 
   * form: thread name, thread state (print as a string RUNNING, BLOCKED, 
   * EXIT, etc), and amount of time run on CPU.
   * 
   */
  void my_threads_state();
  
  #endif
  </code></pre>
  
  <p>Finally, here is myThreads_test.c</p>
  
  <pre><code>/*!
   @file myThreads_test.c
   A test program for testing myThreads.c 
  */
  
  // Assignment 1
  // Author: Georges Krinker
  // Student #: 260369844
  // Course: ECSE 427 (OS)
  // Note: This file has been commented using doxygen style. 
  //       The API can be found at gkrinker.com/locker/OS/pa1
  //       Refer to doxygen.org for more info
  
   /********************************************//**
   *  Includes
   ***********************************************/
  
  #include &lt;stdio.h&gt;      
  #include &lt;stdlib.h&gt;     
  #include "myThreads.h"
  
   /********************************************//**
   *  Global Variables
   ***********************************************/
  
   int mutex;                                         //Mutex used by shared resources 
  
   int a;
   int b;
   int mult;
  
   void multiply() {
      int i;
      for(i=0;i&lt;1000;++i){
      semaphore_wait(mutex);  
      mult=mult+(a*b);
      a++;
      b++;
      semaphore_signal(mutex);    
      }
      mythread_exit();
   }
  
   int main(){
      a=0;
      b=0;
      mult=0;
      mutex=create_semaphore(1);
  
      int threads = 12;                               // How many threads are to be created
      char* names[] = {
          "thread 0",
          "thread 1",
          "thread 2",
          "thread 3",
          "thread 4",
          "thread 5",
          "thread 6",
          "thread 7",
          "thread 8",
          "thread 9",
          "thread 10",
          "thread 11"
      };
  
      mythread_init();                                // Initialize Package
  
      set_quantum_size(50);                           // set quantum to 50
  
      //Create threads
  
      int i=0;
      int dummy = 0;
  
      for(i=0; i&lt;threads; i++)
      {
         dummy=mythread_create(names[i], (void *) &amp;multiply, 100);
      }
  
      runthreads();                               // Run threads
  
      my_threads_state();                         // See state
  
      printf("The value of mult is %d\n", mult);
  
      return 0;
  
   }
  </code></pre>