Защита общих данных и совместное использование одного стека - PullRequest
0 голосов
/ 08 марта 2019

Как защитить общие ресурсы? Необходимо определить, какие строки кода используют общие ресурсы и защищают их. Я предполагаю, что ресурсы pop и push являются общими. Поэтому, чтобы защитить их, я бы поставил эти функции под меткой защиты: как есть private: и public :? Также, как мне сделать 200 потоков, которые я создал, в одном стеке. Обновление: мой профессор сказал, что топ является общим ресурсом.

/*
* Stack containing race conditions
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

// Linked list node
typedef int value_t;
typedef struct Node
{
  value_t data;
  struct Node *next;
} StackNode;



// Stack function declarations
void push(value_t v, StackNode **top);
value_t pop(StackNode **top);
int is_empty(StackNode *top);

pthread_mutex_t mutex; 

//--Tom  This is the wrong function signature for thread entry functions
void *testStack(void *arg)
{
  StackNode *top = NULL;
  for (int i = 0; i < 500; i++)
  {

     pthread_mutex_lock(&mutex);

    // --Tom  Mix these up a bit more
    push(5, &top);
    pop(&top);
    push(6, &top);
    pop(&top);
    push(15, &top);


    pop(&top);
    pthread_mutex_unlock(&mutex);

  }
  pthread_exit(0);
}




int main(int argc, char *argv[])
{
  //--Tom   defining mutex on the stack is not a good choice.  Threads don't share data on the stack

  pthread_mutex_init(&mutex, NULL);




  for (int i = 0; i < 200; i++)
  {
    pthread_t tid;
    pthread_attr_t attr;

    pthread_attr_init(&attr);

    //--Tom this is the wrong place to lock.  Need something that sourounds only the code accessing shared resources

    //--Tom argv[1] in not what yo want to pass the thread
    pthread_create(&tid, &attr, testStack, NULL);

    //--Tom  You are not allowingthe threads to run in parallel


  }

  return 0;
}

// Stack function definitions
void push(value_t v, StackNode **top)
{
  //--Tom  you have not identified the critical lines of code and protected them
  StackNode *new_node = malloc(sizeof(StackNode));

  new_node->data = v;
  new_node->next = *top;
  *top = new_node;
}

value_t pop(StackNode **top)
{
  //--Tom  you have not identified the critical lines of code and protected them
  if (is_empty(*top))
    return (value_t)0;

  value_t data = (*top)->data;
  StackNode *temp = *top;
  *top = (*top)->next;

  free(temp);

  return data;
}

int is_empty(StackNode *top)
{
  //--Tom  you have not identified the critical lines of code and protected them
  if (top == NULL)
    return 1;
  else
    return 0;
}

1 Ответ

1 голос
/ 08 марта 2019

как сделать, чтобы 200 созданных мной потоков имели общий стек

Первая возможность - иметь глобальную переменную StackNode *top;, но это проблема, если вы хотите повторно использовать один и тот же код для разных стеков.

Во-вторых, эта переменная должна быть локальной в main и давать ее адрес в параметре при запуске нового потока вместо NULL , который вы в настоящее время есть, то arg из testStack фактически является StackNode **


Не управляйте мьютексом до / после вызова push / pop , управляйте им внутри функций, иначе существует высокий риск забыть защиту. Таким образом, мьютекст не появляется в testStack . В этом случае предупреждение, см. Мой комментарий о is_empty


int is_empty(StackNode *top)
{
  //--Tom  you have not identified the critical lines of code and protected them
  if (top == NULL)
    return 1;
  else
    return 0;
}

почему так сложно?

int is_empty(StackNode *top)
{
  //--Tom  you have not identified the critical lines of code and protected them
  return (top == NULL);
}

Да, стек не изменен и не смотрит внутрь, поэтому не критичен только для пустой точки зрения, поэтому предупреждение:

/* ptop is a StackNode ** */
if (!is_empty(*ptop)) 
  // here the stack can be empty anyway because an other thread got the CPU
  pop(ptop);

Если вы хотите предложить область защиты, в которой вы можете выполнять несколько операций, это должно быть сделано с использованием одного и того же мьютекса (возможно, скрытого функциями regionEnter и regionExit ) и потому что он также будет блокировать / разблокировать внутри вызываемой функции, что mutex должно быть рекурсивным (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)


Может быть интересно скрыть мьютекс , группирующий его и top в другой структуре, что позволяет не использовать мьютекс для разных стеков

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...