多线程斐波那契对程序

问题描述 投票:1回答:1

我正在尝试编写一个创建两个线程的程序:“前端”和“后端”线程。我想创建一个“后端”线程来迭代和计算斐波那契序列中的术语对,并将它们放入一个数组中,并创建一个“前端”线程,该线程将在每次迭代时打印出该数组对。

“ Front-End”线程-用于在每次迭代中显示“ Back-End”线程操作的结果

“后端”线程-用于计算和设置数组

即[5,8],并在迭代后将包含[13,21]

我正在努力在线程中实现斐波那契序列部分,并且取得了以下进展:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>

int fib;
void *front_end(void *ptr);
void *back_end(void *ptr);

int main() {
  pthread_t thread1, thread2;

  int arr[2] = {5,8};
  const int *ptrtoarr;
  ptrtoarr=arr;

  int create1, create2;

  int *s=(int *)(ptrtoarr);
  printf("%d \n", *s);
  ptrtoarr++;
  s = (int *)(ptrtoarr);
  printf("%d \n", *s);
  ptrtoarr--;

  create1 = pthread_create(&thread1, NULL, back_end, &arr);

  if(create1) {
    fprintf(stderr,"Error - pthread_create() return code: %d\n",create1);
    exit(EXIT_FAILURE);
  }

  pthread_join(thread1, NULL);

  //pthread_join(thread2, NULL);
}

// front-end thread to be callback for each back-end iteration
void *front_end(void *ptr) {
  int *sum = ptr;
  int i, upper = atoi(ptr);

  if (upper > 0) {
    for (i=0; i<upper; i++){

//Print the fib pairs

    }
  }
  pthread_exit(0);
}

void *back_end(void *ptr) {
  int i, upper = atoi(ptr);
  fib=1;

  if(upper > 0) {
    int pre1 = 0;
    int current;

    //calc fib numbers.....
    if(fib == 1){
      printf("")

    }
  }

}

有人可以指导我逐步解决这个问题吗?

c arrays multithreading pthreads fibonacci
1个回答
0
投票

您的骨骼需要工作。

假设以下内容:

unsigned n = ...;
unsigned n_ready = 0; // How many are ready to print
unsigned *fibs = malloc(sizeof(unsigned)*n);
fibs[0] = 0;
fibs[1] = 1;

在后端工作人员的核心,您将有

for (unsigned i=2; i<n; ++i) {
   fibs[i] = fibs[i-2] + fibs[i-1];
   n_ready = i+1;
}

在您的前端工作人员的核心,您将有

for (unsigned i=0; i<n; ++i) {
   while (i >= n_ready)
      /* Nothing */;

   printf("%u\n", fibs[i]);
}

问题1

如果一个线程在另一个变量写入变量时尝试读取该变量,则会遇到问题。两个或多个线程同时读取同一变量是可以的。

两个线程使用的变量是nfib[]n_ready的元素。

  • n:任一线程均未更改,因此我们无需控制对其的访问。

  • [fib[i] for i >= n_ready:仅由后端工作人员访问,因此我们无需控制对这些对象的访问。

  • [fib[i] for i < n_ready:仅由前端工作人员访问,因此我们无需控制对这些访问。”]]

  • n_ready:后端工作人员可以随时设置n_ready,而前端工作人员可以随时尝试读取n_ready,因此我们确实需要控制对n_ready的访问。

  • Mutex通常用于确保一次只有一个线程正在访问资源(例如,变量,变量组,文件句柄等)。

我们的后端工作人员成为

for (unsigned i=2; i<n; ++i) {
   // The mutex only protects n_ready
   // --nothing is going to touch fib[i]--
   // so we don't need to obtain a lock yet.
   pthread_mutex_unlock(&mutex);
   fibs[i] = fibs[i-2] + fibs[i-1];

   // We need to access n_ready.
   pthread_mutex_lock(&mutex);
   n_ready = i+1;
   pthread_mutex_unlock(&mutex);
}

我们的前端工作者成为

for (unsigned i=0; i<n; ++i) {
   // We need to access n_ready.
   pthread_mutex_lock(&mutex);
   while (i >= n_ready) {
      // Allow other thread to gain the lock.
      pthread_mutex_unlock(&mutex);

      // We need to access n_ready.
      pthread_mutex_lock(&mutex);
   }

   // The mutex only protects n_ready
   // --nothing is going to change fib[i]--
   // so we can release it now rather than later.
   pthread_mutex_unlock(&mutex);

   printf("%u\n", fibs[i]);
}

问题2

您有一个忙碌的循环。通常,这很糟糕,因为这意味着您的线程正在使用100%的等待时间。 (在这种特殊情况下,由于i >= n_ready可能已经是对的,这实际上是一个不错的策略。但是让我们忽略它。)一个线程可以休眠,直到另一个线程使用条件vars发出信号为止。]

我们的后端工作人员成为

for (unsigned i=2; i<n; ++i) {
   // The mutex only protects n_ready
   // --nothing is going to touch fib[i]--
   // so we don't need to obtain a lock yet.
   fibs[i] = fibs[i-2] + fibs[i-1];

   // We need to access n_ready.
   pthread_mutex_lock(&mutex);
   n_ready = i+1;
   // Wake up the other thread if it's blocked.
   pthread_cond_signal(&cond);
   pthread_mutex_unlock(&mutex);
}

我们的前端工作者成为

for (unsigned i=0; i<n; ++i) {
   // We need to access n_ready.
   pthread_mutex_lock(&mutex);
   while (i >= n_ready)
      pthread_cond_wait(&cond, &mutex);

   // The mutex only protects n_ready
   // --nothing is going to change fib[i]--
   // so we can release it now rather than later.
   pthread_mutex_unlock(&mutex);

   printf("%u\n", fibs[i]);
}

始终在锁定的互斥锁上调用pthread_cond_wait。互斥量在调用时将解锁,并在返回之前将其锁定。这允许另一个线程获取互斥体以更改n_ready


完整代码:

#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define UNUSED(x) (void)(x)


// To control access to n_ready.
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static unsigned n_ready = 0; // How many are ready to print

static unsigned n;
static unsigned *fibs = NULL;


static void *back_worker(void *unused) {
   UNUSED(unused);

   fibs[0] = 0;
   fibs[1] = 1;

   // We need to access n_ready.
   pthread_mutex_lock(&mutex);
   n_ready = 2;
   // Wake up the other thread if it's blocked.
   pthread_cond_signal(&cond);
   pthread_mutex_unlock(&mutex);

   for (unsigned i=2; i<n; ++i) {
      // The mutex only protects n_ready
      // --nothing is going to touch fib[i]--
      // so we don't need to obtain a lock yet.
      fibs[i] = fibs[i-2] + fibs[i-1];

      // We need to access n_ready.
      pthread_mutex_lock(&mutex);
      n_ready = i+1;
      // Wake up the other thread if it's blocked.
      pthread_cond_signal(&cond);
      pthread_mutex_unlock(&mutex);
   }

   return NULL;
}


static void *front_worker(void *unused) {
   UNUSED(unused);

   for (unsigned i=0; i<n; ++i) {
      // We need to access n_ready.
      pthread_mutex_lock(&mutex);
      while (i >= n_ready)
         pthread_cond_wait(&cond, &mutex);

      // The mutex only protects n_ready
      // --nothing is going to change fib[i]--
      // so we can release it now rather than later.
      pthread_mutex_unlock(&mutex);

      printf("%u\n", fibs[i]);
   }

   return NULL;
}


int main(void) {
   n = 20;  // How many to generate.

   fibs = malloc(sizeof(unsigned) * n);

   pthread_t back_thread;
   if (errno = pthread_create(&back_thread, NULL, back_worker, NULL)) {
      perror(NULL);
      exit(1);
   }

   pthread_t front_thread;
   if (errno = pthread_create(&front_thread, NULL, front_worker, NULL)) {
      perror(NULL);
      exit(1);
   }

   pthread_join(back_thread, NULL);
   pthread_join(front_thread, NULL);

   pthread_cond_destroy(&cond);
   pthread_mutex_destroy(&mutex);
   free(fibs);

   return 0;
}

输出:

$ gcc -Wall -Wextra -pedantic a.c -o a -lpthread && a
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
© www.soinside.com 2019 - 2024. All rights reserved.