void *thread_run(void *ptr) {
  int retcode;
  struct thread_arg *arg = (struct thread_arg *) ptr;
  char **strings = arg->arr.strings;
  int len = arg->arr.len;
  int idx = arg->thread_idx;
  
  if (use_psort) {
    switch (selected_mt_sort_type) {
    case MT_HEAP_SORT:
      parallel_hsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, psort_internal_threads);
      break;
    case MT_TERNARY_HEAP_SORT:
      parallel_ternary_hsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, psort_internal_threads);
      break;
    case MT_QUICK_SORT:
      parallel_qsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, psort_internal_threads);
      break;
    case MT_FLASH_SORT:
      parallel_fsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, metric_str_full, (void *) NULL, psort_internal_threads);
      break;
    case MT_FLASH_SORT_BIN:
      parallel_fsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, metric_binary_printable_pref, (void *) NULL, psort_internal_threads);
      break;
    case MT_INSERTION_SORT:
      parallel_isort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, psort_internal_threads);
      break;
    case MT_MERGE_SORT:
      parallel_msort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, psort_internal_threads);
      break;
    default:
      /* should *never* happen: */
      handle_error_myerrno(-1, -1, "wrong mt_sort_type", PROCESS_EXIT);
    }
  } else {
    switch (selected_mt_sort_type) {
    case MT_HEAP_SORT:
      hsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL);
      break;
    case MT_TERNARY_HEAP_SORT:
      ternary_hsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL);
      break;
    case MT_QUICK_SORT:
      qsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL);
      break;
    case MT_FLASH_SORT:
      fsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, metric_str_full, (void *) NULL);
      break;
    case MT_FLASH_SORT_BIN:
      fsort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL, metric_binary_printable_pref, (void *) NULL);
      break;
    case MT_INSERTION_SORT:
      isort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL);
      break;
    case MT_MERGE_SORT:
      msort_r(strings, len, sizeof(char_ptr), compare_str_full, (void *) NULL);
      break;
    default:
      /* should *never* happen: */
      handle_error_myerrno(-1, -1, "wrong mt_sort_type", PROCESS_EXIT);
    }
  }

  for (int step = 1; step < thread_count; step *= 2) {
    retcode = pthread_barrier_wait(& barrier);
    if (retcode == PTHREAD_BARRIER_SERIAL_THREAD) {
      pthread_mutex_lock(&output_mutex);
      /* printf("thread %ld (%d) is PTHREAD_BARRIER_SERIAL_THREAD=%d\n", (long) id, tid, retcode); */
      pthread_mutex_unlock(&output_mutex);
    } else {
      handle_thread_error(retcode, "pthread_barrier_wait", THREAD_EXIT);
    }

    if (idx % (2*step) == 0) {
      int other_idx = idx + step;
      if (other_idx < thread_count) {
        int i = 0;
        int j = 0;
        int k = 0;
        int m = segments[idx].arr.len;
        int n = segments[other_idx].arr.len;
        int total_len = m + n;
        char_ptr *strings = malloc(total_len * sizeof(char_ptr));
        char_ptr *left = segments[idx].arr.strings;
        char_ptr *right = segments[other_idx].arr.strings;
        while (i+j < total_len) {
          if (i >= m) {
            while (j < n) {
              strings[k++] = right[j++];
            }
          } else if (j >= n) {
            while (i < m) {
              strings[k++] = left[i++];
            }
          } else {
            if (strcmp(left[i], right[j]) <= 0) {
              strings[k++] = left[i++];
            } else {
              strings[k++] = right[j++];
            }
          }
        }
        segments[idx].arr.len = total_len;
        segments[idx].arr.strings = strings;
        segments[other_idx].arr.len = 0;
        segments[other_idx].arr.strings = NULL;
      }
    }
  }
  return (void *) NULL;
}
void handle_error(int return_code) {
  if (return_code < 0) {
    int myerrno = errno;
    handle_error_myerrno(return_code, myerrno);
  }
}
Beispiel #3
0
void fsort_f(void *base,
             size_t nmemb,
             size_t size,
             double factor,
             compare_fun3 compare,
             void *argc,
             metric_fun2 metric,
             void *argm) {
  if (nmemb <= 1) {
    /* nothing to sort */
    return;
  }

  /* preparation: form classes */
  /* use calculate_k for a purpose it has not been made for, but since it is identical with what is needed here it is correct */
  size_t lsize = calculate_k(nmemb, factor, nmemb) + 1;
  if (lsize < 2) {
    lsize = 2;
  }
  size_t *l = (size_t *) malloc(lsize * sizeof(size_t));
  handle_ptr_error(l, "malloc for l", PROCESS_EXIT);
  for (size_t k = 0; k < lsize; k++) {
    l[k] = 0;
  }
  //size_t idx_min = 0;
  void *amin = POINTER(base, 0, size);
  size_t idx_max = 0;
  void *amax = POINTER(base, idx_max, size);
  for (size_t i = 0; i < nmemb; i++) {
    if (compare(POINTER(base, i, size), amin, argc) < 0) {
      // idx_min = i;
      amin = POINTER(base, i, size);
    }
    if (compare(POINTER(base, i, size), amax, argc) > 0) {
      idx_max = i;
      amax = POINTER(base, i, size);
    }
  }
  if (compare(amin, amax, argc) == 0) {
    /* min and max are the same --> already sorted */
    free(l);
    return;
  }
  double amin_metric = metric(amin, argm);
  double amax_metric = metric(amax, argm);
  double step = (lsize - 1)/(amax_metric - amin_metric);
  /* size_t k_min = calculate_k(step, 0, lsize); */
  /* size_t k_max = calculate_k(step, amax_metric - amin_metric, lsize); */

  /* count the elements in each of the lsize classes */
  for (size_t i = 0; i < nmemb; i++) {
    double ai_metric = metric(POINTER(base, i, size), argm);
    size_t k = calculate_k(step, ai_metric - amin_metric, lsize);
    l[k]++;
  }

  /* find the start positions for each of the classes */
  size_t *ll = (size_t *) malloc((lsize + 1) * sizeof(size_t));
  handle_ptr_error(ll, "malloc for ll", PROCESS_EXIT);
  ll[0] = 0;
  ll[1] = l[0];

  for (size_t k = 1; k < lsize; k++) {
    l[k] += l[k-1];
    ll[k+1] = l[k];
  }

  swap_elements(POINTER(base, 0, size), POINTER(base, idx_max, size), size);
  // printf("prepared\n");

  /* do the permutation */
  size_t nmove = 0;
  size_t j = 0;
  size_t k = lsize - 1;
  while (nmove < nmemb - 1) {
    while (j >= l[k]) {
      j++;
      k = calculate_k(step, metric(POINTER(base, j, size), argm) - amin_metric, lsize);
    }
    /* now: j < l[k] */
    void *flash_ptr = alloca(size);
    handle_ptr_error(flash_ptr, "alloca for flash_ptr", PROCESS_EXIT);
    /* flash_ptr takes element a[j] such that j > l[k] */
    memcpy(flash_ptr, POINTER(base, j, size), size);
    while (j != l[k]) {
      k = calculate_k(step, metric(flash_ptr, argm) - amin_metric, lsize);
      void *alkm_ptr = POINTER(base, l[k]-1, size);
      swap_elements(flash_ptr, alkm_ptr, size);
      l[k]--;
      nmove++;
    }
  }

  /* use qsort or hsort for each class */
  for (k = 0; k < lsize; k++) {
    size_t n = ll[k+1] - ll[k];
    if (n > 1 && ll[k+1] < ll[k] || n > nmemb) {
      char txt[4096];
      sprintf(txt, "wrong order: k=%ld lsize=%ld nmemb=%ld n=%ld ll[k]=%ld ll[k+1]=%ld\n", k, lsize, nmemb, n, ll[k], ll[k+1]);
      handle_error_myerrno(-1, EDOM, txt, PROCESS_EXIT);
    }
    if (n > 7) {
      void *basek = POINTER(base, ll[k], size);
      hsort_r(basek, n, size, compare, argc);
    } else  if (n > 1) {
      void *basek = POINTER(base, ll[k], size);
      isort_r(basek, n, size, compare, argc);
    }
  }
  free(l);
  l = NULL;
  free(ll);
  ll = NULL;
  return;
}