Squeak.ru - шаблоны программирования

Попытка понять условия гонки/потоки в C

Для статеров: я студент, который не был бакалавром CS, но перешел в магистратуру CS. Поэтому я приветствую любую помощь, которую кто-либо готов оказать.

Цель этого состояла в том, чтобы создать N потоков между 2-4, а затем, используя случайно сгенерированный массив символов нижнего регистра, сделать их прописными.

Это нужно было сделать, используя N потоков (определяемых командной строкой при выполнении), разделив работу как можно более равномерно, используя pthread.

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

Я также изо всех сил пытаюсь понять разделение работы между потоками. Насколько я понимаю (поправьте меня, если я ошибаюсь), в общем случае функционирование потоков будет выбираться случайным образом во время выполнения. Итак, я предполагаю, что мне нужно сделать что-то вроде динамического разделения массива на N потоков и настроить его так, чтобы каждый поток выполнял верхний регистр части массива того же размера?

Я знаю, что, вероятно, есть ряд других несоответствий, которые мне нужно исправить в моем коде, но я не долго программировал и только начал использовать C/C++ около месяца назад.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <ctype.h>

//Global variable for threads
char randChars[60];
int j=0;

//Used to avoid race conditions
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;

//Establish the threads
void* upperThread(void* argp)
{
    while(randChars[j])
    {
        pthread_mutex_lock( &mutex1 );
        putchar (toupper(randChars[j]));
        j++;
        pthread_mutex_unlock( &mutex1 );
    }

return NULL;

}

int main(int argc, char **argv)
{
    //Initializae variables and thread
    int N,randNum,t;
    long i;
    pthread_t pth[N];
    pthread_mutex_init(&mutex1, NULL);
    char randChar = ' ';

    //Check number of command inputs given
    if(argc!=2)
    {
        fprintf(stderr,"usage: %s <enter a value for N>\n", argv[0]);
        exit(0);
    }

    N = atoi(argv[1]);

    //Checks command inputs for correct values
    if(N<2||N>4){
        printf("Please input a value between 2 and 4 for the number of threads.\n");
        exit(0);
    }

    //Seed random to create a randomized value
    srand(time(NULL));
    printf("original lower case version:\n");

    for (i=0; i<61; i++)
    {
        //Generate a random integer in lower alphabetical range
        randNum = rand()%26;
        randNum = randNum+97;

        //Convert int to char and add to array
        randChar = (char) randNum;
        randChars[i] = randChar;
        printf("%c", randChar);
    }

    //Create N threads
    for (i=0; i<N; i++)
    {
        pthread_create(pth + i, NULL, upperThread, (void *)i);
    }

    printf("\n\nupper case version:\n");

    //Join the threads
    for(t=0; t < N; t++)
    {
        pthread_join(pth[t], NULL);
    }
    printf("\n");

    pthread_exit(NULL);

    return 0;
}

  • Эта попытка - пустая затея. Все потоки пытаются изменить один и тот же объект и будут просто наступать друг на друга. В результате ваш код будет тратить почти все свое время на координацию потоков и почти не будет тратить время на реальную полезную работу. 18.03.2018
  • Я боялся, что, возможно, так оно и было, поскольку казалось, что они все вместе пытались сделать одно и то же. Однако, спасибо. 18.03.2018
  • Потоки обращаются к глобальной переменной j вне какой-либо блокировки, что является состоянием гонки. Если вы хотите, чтобы каждый поток работал с другим/непересекающимся подмножеством массива, лучший способ сделать это — передать каждому потоку минимальное и максимальное значения индекса, с которыми вы хотите, чтобы он работал; тогда каждый поток может работать параллельно без необходимости мьютекса (и без условий гонки, поскольку они не обращаются к каким-либо общим переменным) 18.03.2018

Ответы:


1

Приведенный вами пример не является хорошей многопоточной программой. Причина в том, что ваши потоки будут постоянно ждать того, который держит блокировку. Что в основном делает вашу программу последовательной. Я бы изменил ваш upperThread на

void* upperThread(void* argp){
    int temp;
    while(randChars[j]){
            pthread_mutex_lock( &mutex1 );
            temp = j;     
            j++;
            pthread_mutex_unlock( &mutex1 );

            putchar (toupper(randChars[temp]));
        }

    return NULL;

}

Таким образом, ваши потоки будут ждать того, который удерживает блокировку, пока он не извлечет значение j , не увеличит его и не освободит блокировку, а затем не выполнит остальные операции.

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

18.03.2018
Новые материалы

Угловая структура архитектуры
Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

«Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

Создайте API с помощью Python FastAPI
Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

Веселье с прокси-сервером JavaScript
Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...