title: Threads synchronization in C: why do they overlap
body: <p>I have some code, written in C, I'd like to ask you about:</p>
  
  <pre><code>#include &lt;stdlib.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;pthread.h&gt;
  
  #define COLOR_YELLOW  "\x1b[33m"
  #define COLOR_RED    "\x1b[31m"
  #define COLOR_RESET   "\x1b[0m"
  
  int tests = 3;
  int running_servers;
  
  int servers;
  int clients;
  int max_clients;
  
  int current_id = 0;
  int clients_handled = 0;
  
  
  void *server(void *arg);
  void *client(void *arg);
  
  pthread_mutex_t server_mutex;
  pthread_mutex_t client_mutex;
  
  pthread_cond_t order_cond;
  pthread_cond_t getting_clients;
  pthread_cond_t full;
  
  int main(int argc, char *argv[]) {
  
       if(argc != 4) { printf("expected 3 arguments"); return 1; }
  
       // INIT
       servers = atoi(argv[1]);
       running_servers = atoi(argv[1]);
       clients = atoi(argv[2]);
       max_clients = atoi(argv[3]);
  
       pthread_mutex_init(&amp;server_mutex, NULL);
       pthread_mutex_init(&amp;client_mutex, NULL);
  
       pthread_cond_init(&amp;order_cond, NULL);
       pthread_cond_init(&amp;getting_clients, NULL);
       pthread_cond_init(&amp;full, NULL);
  
       pthread_t *server_thread = calloc(servers, sizeof(pthread_t));
       pthread_t *client_thread = calloc(clients, sizeof(pthread_t));
  
  
  
       // CREATING CLIENT THREADS
       int *arg;
       for (int i = 0; i &lt; clients; i++) {
           arg = malloc(sizeof(int));
           *arg = i;
           if (pthread_create(&amp;client_thread[i], NULL, client, (void *) arg))
               perror("pthread_create error for passenger");
       }
  
  
       // CREATING SERVER THREADS
       for (int i = 0; i &lt; servers; i++) {
           arg = malloc(sizeof(int));
           *arg = i;
           if (pthread_create(&amp;server_thread[i], NULL, server, (void *) arg))
               perror("pthread_create error for car");
       }
  
       // JOINING ENDING THREADS
       for (int i = 0; i &lt; servers; i++)
           if (pthread_join(server_thread[i], NULL)) perror("pthread_join error for car");
  
  
       for (int i = 0; i &lt; clients; i++)
           if (pthread_join(client_thread[i], NULL)) perror("pthread_join error for passenger");
  
       return 0;
  }
  
  
  void *server(void *arg) {
       int id = *(int *) arg;
  
  
       printf(COLOR_RED "SERVER: %d" COLOR_RESET " start working\n", id);
  
       while (tests--) {
  
           // ONLY ONE SERVER CAN WORK - SERVERS ARE RUN IN ORDER
           pthread_mutex_lock(&amp;server_mutex);
           while (id != current_id)
               pthread_cond_wait(&amp;order_cond, &amp;server_mutex);
  
  
           printf(COLOR_RED "SERVER: %d" COLOR_RESET " starts\n", id);
  
  
           printf(COLOR_RED "SERVER: %d" COLOR_RESET " gets clients \n", id);  // server gets clients
           pthread_cond_broadcast(&amp;getting_clients);
  
  
           pthread_cond_wait(&amp;full, &amp;client_mutex);                            // server is waiting for signal (from any client)
           printf(COLOR_RED "SERVER: %d" COLOR_RESET " is full \n", id);       // that he has max number of clients
  
  
  
           printf(COLOR_RED "SERVER: %d" COLOR_RESET " stops \n", id);
  
           current_id = (current_id + 1) % servers;
  
           pthread_mutex_unlock(&amp;server_mutex);
           pthread_cond_broadcast(&amp;order_cond);
       }
  
       running_servers -= 1;
       return NULL;
  }
  
  
  
  
  void *client(void *arg) {
       int id = *(int *) arg;
  
  
       printf(COLOR_YELLOW "CLIENT: %d" COLOR_RESET " starts\n", id);
  
       while (running_servers) {
           pthread_mutex_lock(&amp;client_mutex);                      // only one client at the time (should be)
  
           pthread_cond_wait(&amp;getting_clients, &amp;client_mutex);
  
           printf(COLOR_YELLOW "CLIENT: %d" COLOR_RESET " has access to server %d\n", id,current_id);
  
           clients_handled++;
  
  
           for (int j = 0; j &lt; 10; j++) {                          // client writes some numbers
               printf("%d:    ", id);
               for (int i = 0; i &lt; 10; i++) {
                   printf("%d  ", 10 * j + i);
               }
               printf("\n");
           }
  
           if(clients_handled == max_clients) {                    // client sends signal he is the last one server can handle
               printf(COLOR_YELLOW "CLIENT: %d" COLOR_RESET " server %d is full, shifting to next server\n", id, current_id);
               clients_handled = 0;
               pthread_cond_signal(&amp;full);
           }
  
           pthread_mutex_unlock(&amp;client_mutex);
  
       }
  
       return NULL;
  }
  </code></pre>
  
  <p>it's not pretty but it's working (sort of).</p>
  
  <p><strong>How it works:</strong>
  Program gets 3 arguments: number of servers, number of clients, max clients in server. We have servers and clients created as threads. At the moment one client and one server should be active (for that are mutexes server_mutex and client_mutex). Server broadcast info he is active (getting_clients condition), clients are run one next to each other, client writes some numbers, if he is the last one server can handle he signals it (full cond) and server is switchet to next one. I hope you won;t have any problems with running it (as I wrote is works - sort of).</p>
  
  <p><strong>What does not work</strong></p>
  
  <ul>
  <li><p>it looks like server_mutex does his job, servers are being run one by one, but client_mutex doesn't, and I don't know why sometimes clients overlap - one client starts, while other haven't finished writing numbers.</p></li>
  <li><p>I have problem with first broadcast of getting_clients, because from unknown reason it is sometimes send while some clients are not yet created. This is especially bad, when I have like 3 servers and 2 clients, and then they may not even start. It's weird for me because client threads are being created first, and I wonder if there is any solution ( except adding sleep() between creating client threads and server threads, but I'd like to avoid that)</p></li>
  <li><p>for some reason program doesn't end, it just stops in one moment, that may be connected with previous ones, but I haven't found the sollution for that yet,</p></li>
  <li><p>do you have any ideas what to do, to make all clients be handled equally? I mean I have 3 servers and 100 clients and I wouldn't like to have the situation when few clients write all the time and there is a group which haven't got an access to server yet</p></li>
  </ul>
  
  <p>I will be grateful for any help :)</p>