CS162 operating system HW2 (using Linx kernel linked list and multithreading to implement WordCounter)

Experience

IDE automatic prompt completion is really important, which greatly improves development efficiency. The library function API is automatically searched through the IDE.

GDB debugging capabilities should be strengthened.

 

Use the list.h provided above to rewrite the wordCount program. The implementation of the header file is quite skillful. The external list library will be used. Multithreading will be defined in the same code with macros. This is a common skill for C/C++ development.

There are some differences between the implementation of the linked list in the Linux kernel and the traditional one.

word_count.h

#ifdef PINTOS_LIST
#include "list.h"
typedef struct word_count {
  char* word;
  int count;
  struct list_elem elem;
} word_count_t;

#ifdef PTHREADS
#include <pthread.h>
typedef struct word_count_list {
  struct list lst;
  pthread_mutex_t lock;
} word_count_list_t;
#else  /* PTHREADS */
typedef struct list word_count_list_t;
#endif /* PTHREADS */

#else  /* PINTOS_LIST */

typedef struct word_count {
  char* word;
  int count;
  struct word_count* next;
} word_count_t;

typedef word_count_t* word_count_list_t;
#endif /* PINTOS_LIST */

/* Initialize a word count list. */
void init_words(word_count_list_t* wclist);

/* Get length of a word count list. */
size_t len_words(word_count_list_t* wclist);

/* Find a word in a word_count list. */
word_count_t* find_word(word_count_list_t* wclist, char* word);

/*
 * Insert word with count=1, if not already present; increment count if
 * present. Takes ownership of word.
 */
word_count_t* add_word(word_count_list_t* wclist, char* word);

/* Print word counts to a file. */
void fprint_words(word_count_list_t* wclist, FILE* outfile);

/* Sort a word count list using the provided comparator function. */
void wordcount_sort(word_count_list_t* wclist, bool less(const word_count_t*, const word_count_t*));

#endif /* WORD_COUNT_H */

word_count_l.c single thread implementation

#ifndef PINTOS_LIST
#error "PINTOS_LIST must be #define'd when compiling word_count_l.c"
#endif

#include "word_count.h"

void init_words(word_count_list_t* wclist) {
  list_init(wclist);
  return;
}

size_t len_words(word_count_list_t* wclist) {
  return list_size(wclist);
}

word_count_t* find_word(word_count_list_t* wclist, char* word) {
  struct list_elem *e;
  for(e=list_begin(wclist);e!=list_end(wclist);e=list_next(e)){
    word_count_t* p = list_entry(e,word_count_t, elem);
    if(strcmp(p->word,word)==0){
      return p;
    }
  }
  return NULL;
}

word_count_t* add_word(word_count_list_t* wclist, char* word) {
  word_count_t* p = find_word(wclist,word);
  if(p!=NULL){
    p->count++;
    return p;
  }
  word_count_t* tmp = (word_count_t*)malloc(sizeof(word_count_t));
  tmp->count = 1;
  tmp->word = word; 
  list_push_back(wclist,&tmp->elem);
  return tmp;
}

void fprint_words(word_count_list_t* wclist, FILE* outfile) {
  struct list_elem *e;
  for (e = list_begin (wclist); e != list_end(wclist);e = list_next (e)){
    word_count_t *wc = list_entry(e, word_count_t, elem);
    fprintf(outfile, "%8d\t%s\n", wc->count, wc->word);
  }
}

static bool less_list(const struct list_elem* ewc1, const struct list_elem* ewc2, void* aux) {
  /* TODO */
  bool (*less)(const word_count_t *, const word_count_t *) = aux;
  word_count_t *wc1 = list_entry(ewc1, word_count_t, elem);
  word_count_t *wc2 = list_entry(ewc2, word_count_t, elem);
  return less(wc1, wc2);
}

void wordcount_sort(word_count_list_t* wclist,
                    bool less(const word_count_t*, const word_count_t*)) {
  list_sort(wclist, less_list, less);
}

The implementation of multi-threading is very simple. When inserting, ensure that the thread is complete and lock it. Note that the definition of the structure changes.

#ifndef PINTOS_LIST
#error "PINTOS_LIST must be #define'd when compiling word_count_lp.c"
#endif

#ifndef PTHREADS
#error "PTHREADS must be #define'd when compiling word_count_lp.c"
#endif

#include "word_count.h"

void init_words(word_count_list_t* wclist) {
  list_init(&wclist->lst);
  pthread_mutex_init(&wclist->lock, NULL);
}

size_t len_words(word_count_list_t* wclist) {
  return list_size(&wclist->lst);
}

word_count_t* find_word(word_count_list_t* wclist, char* word) {
  struct list_elem *e;
  for(e=list_begin(&wclist->lst);e!=list_end(&wclist->lst);e=list_next(e)){
    word_count_t* p = list_entry(e,word_count_t, elem);
    if(strcmp(p->word,word)==0){
      return p;
    }
  }
  return NULL;
}

word_count_t* add_word(word_count_list_t* wclist, char* word) {
  pthread_mutex_lock(&wclist->lock);
  word_count_t* p = find_word(wclist,word);
  if(p!=NULL){
    p->count++;
  }else{
    p = (word_count_t*)malloc(sizeof(word_count_t));
    p->count = 1;
    p->word = word;
    list_push_front(&wclist->lst,&p->elem);
  }
  pthread_mutex_unlock(&wclist->lock);
  return p;
}

void fprint_words(word_count_list_t* wclist, FILE* outfile) { /* TODO */
  struct list_elem *e;
  for (e = list_begin(&wclist->lst);e!=list_end(&wclist->lst);e=list_next(e)){
    word_count_t *wc = list_entry(e, word_count_t, elem);
    fprintf(outfile, "%8d\t%s\n", wc->count, wc->word);
  }
}

static bool less_list(const struct list_elem* ewc1, const struct list_elem* ewc2, void* aux) {
  /* TODO */
  bool (*less)(const word_count_t *, const word_count_t *) = aux;
  word_count_t *wc1 = list_entry(ewc1, word_count_t, elem);
  word_count_t *wc2 = list_entry(ewc2, word_count_t, elem);
  return less(wc1, wc2);
}

void wordcount_sort(word_count_list_t* wclist,
                    bool less(const word_count_t*, const word_count_t*)) {
  list_sort(&wclist->lst, less_list, less);
}

Look at the main function

typedef struct thread_word_args
{
  word_count_list_t* word_counts;
  char* filename;
} targs_t;

void *threadfun(void *arg) {
  targs_t* targs = (targs_t*)arg;
  FILE *infile = fopen(targs->filename, "r");
  if (infile == NULL) {
    perror("fopen");
    pthread_exit(NULL);
  }
  // pthread_mutex_lock(&targs->word_counts->lock);
  count_words(targs->word_counts, infile);
  // pthread_mutex_unlock(&targs->word_counts->lock);
  fclose(infile);
  pthread_exit(NULL);
}

/*
 * main - handle command line, spawning one thread per file.
 */
int main(int argc, char* argv[]) {
  /* Create the empty data structure. */
  word_count_list_t word_counts;
  init_words(&word_counts);

  if (argc <= 1) {
    /* Process stdin in a single thread. */
    count_words(&word_counts, stdin);
  } else {
    int nthreads = argc - 1;
    pthread_t threads[nthreads];
    for(int i=0;i<nthreads;i++){
      targs_t* targs = (targs_t *) malloc(sizeof(targs_t));
      targs->filename = argv[i+1];
      targs->word_counts = &word_counts;
      int rc = pthread_create(&threads[i], NULL, threadfun, (void *)targs);
      if(rc){
        printf("ERROR; return code from pthread_create() is %d\n", rc);
        exit(-1);
      }
    }
    for(int i=0;i<nthreads;i++){
      pthread_join(threads[i],NULL);
    }
  }

  /* Output final result of all threads' work. */
  wordcount_sort(&word_counts, less_count);
  fprint_words(&word_counts, stdout);
  pthread_exit(NULL);
  return 0;
}

 

Guess you like

Origin blog.csdn.net/wwxy1995/article/details/113828304