multi_thread_copying (void)
{
  pthread_t *workers;
  size_t i;
  int err;

  /* Some invariants that should be true if the main program called us
   * correctly.
   */
  assert (threads > 0);
  assert (threads == connections);
/*
  if (src.ops == &nbd_ops)
    assert (src.u.nbd.handles.size == connections);
  if (dst.ops == &nbd_ops)
    assert (dst.u.nbd.handles.size == connections);
*/
  assert (src->size != -1);

  workers = malloc (sizeof (pthread_t) * threads);
  if (workers == NULL) {
    perror ("malloc");
    exit (EXIT_FAILURE);
  }

  /* Start the worker threads. */
  for (i = 0; i < threads; ++i) {
    err = pthread_create (&workers[i], NULL, worker_thread,
                          (void *)(uintptr_t)i);
    if (err != 0) {
      errno = err;
      perror ("pthread_create");
      exit (EXIT_FAILURE);
    }
  }

  /* Wait until all worker threads exit. */
  for (i = 0; i < threads; ++i) {
    err = pthread_join (workers[i], NULL);
    if (err != 0) {
      errno = err;
      perror ("pthread_join");
      exit (EXIT_FAILURE);
    }
  }

  free (workers);
}
multi_thread_copying (void)
{
  pthread_t *workers;
  size_t i;
  int err;

   
  assert (threads > 0);
  assert (threads == connections);
 
  assert (src->size != -1);

  workers = malloc (sizeof (pthread_t) * threads);
  if (workers == NULL) {
    perror ("malloc");
    exit (EXIT_FAILURE);
  }

   
  for (i = 0; i < threads; ++i) {
    err = pthread_create (&workers[i], NULL, worker_thread,
                          (void *)(uintptr_t)i);
    if (err != 0) {
      errno = err;
      perror ("pthread_create");
      exit (EXIT_FAILURE);
    }
  }

   
  for (i = 0; i < threads; ++i) {
    err = pthread_join (workers[i], NULL);
    if (err != 0) {
      errno = err;
      perror ("pthread_join");
      exit (EXIT_FAILURE);
    }
  }

  free (workers);
}