2015-01-09 3 views
0

Чем больше я пытаюсь это узнать, тем больше я смущаюсь, поэтому я открыт для любых советов и помощи. Благодарю. Программа представляет собой узкий мост (мьютекс) и управляемые машины (процессы) на нем, но только один процесс может пересекать его за один раз. После пересечения мостовой поток может добавить себя в очередь или пойти в город, где он спит, а затем добавить в очередь. Процессы (автомобили) должны запускаться до тех пор, пока программа не будет завершена. При необходимости я могу перевести код на английский. После компиляции выполните так: ./program -n -debug n - количество потоков, отладка - очередь печати, необязательно. Я думаю, что нитки не работают синхронно, например, я запустил программу для 8 потоков и имел поток с номером 34 в очереди. Не знаю, почему, и это произошло после того, как я «исправил» код.Синхронизация потоков Posix с мьютексами

/* 
There's a road(bridge) from city A to B. Only one car can use it to move at a time. 
Cars should run(change cities) all the time, no end of program. 
Access to the bridge should be synchronized with mutexes. Every car have its numer from 1 to N where N is given as first parameter. 
Program should printing something like this when one of printing variable is changing: 
A - 5 10 >> >[>> 4 >> ] << <4 6 - B 
@up That means that in city A is 5 cars, in city A queue is 10 cars (wanting to change city). Thread with numer 4 is changing city from A to B. In city B queue is 4 cars and in city B is 6 cars. 
If second parameter -debug is given, then program should printf queue status. 
*/ 

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

#define true 1 
#define false 0 

pthread_mutex_t countOfQueueA; 
pthread_mutex_t countOfQueueB; 
pthread_mutex_t bridge; 
pthread_mutex_t queueA; 
pthread_mutex_t queueB; 
pthread_mutex_t cityA; 
pthread_mutex_t cityB; 

int inQueueA = 0; // Number of cars in queue of city A 
int inQueueB = 0; // Number of cars in queue of city B 
int inCityA = 0; // Number of cars in city A 
int inCityB = 0; // Number of cars in city B 

int createdThreads = 0; // Number of created threads by pthread_create 
int numberOfCars = 0; // 
int debugMode = 0; // 0 - no, 1 - debug 
int *queueInA; // Pointer to queue in city A 
int *queueInB; // Pointer to queue in city B 



void printQueue(char city) 
{ 
    int i; 
    if (city == 'a') 
    { 
    printf("\nQueue A status: "); 
    for (i = 0; i<numberOfCars; i++) 
    { 
     printf("%d ", queueInA[i]); 
    } 
    printf("\n"); 
    } 
    else if (city == 'b') 
    { 
    printf("\nQueue B status: "); 
    for (i = 0; i<numberOfCars; i++) 
    { 
     printf("%d ", queueInB[i]); 
    } 
    printf("\n"); 
    } 
} 

void addToQueue(char city, int threadNumber) // Adding at the end of the queue in selected city 
{ 
    if (city == 'a') 
    { 
    pthread_mutex_lock(&queueA); 
    pthread_mutex_lock(&countOfQueueA); 
    int i = 0; 
    while (queueInA[i] != 0) //Looking for first free place = 0 to add car 
    { 
     i++; 
    } 
    queueInA[i] = threadNumber; 
    inQueueA++; 
    printf("\nA-%d %d>>> [ BLANK ] <<<%d %d-B", inCityA, inQueueA, inQueueB, inCityB); 
    if (debugMode == 1) 
    { 
     printQueue(city); 
    } 
    pthread_mutex_unlock(&queueA); 
    pthread_mutex_unlock(&countOfQueueA); 
    } 
    else if (city == 'b') 
    { 
    pthread_mutex_lock(&queueB); 
    pthread_mutex_lock(&countOfQueueB); 
    int i = 0; 
    while (queueInB[i] != 0) 
    { 
     i++; 
    } 
    queueInB[i] = threadNumber; 
    inQueueB++; 
    printf("\nA-%d %d>>> [ BLANK ] <<<%d %d-B", inCityA, inQueueA, inQueueB, inCityB); 
    if (debugMode == 1) 
    { 
     printQueue(city); 
    } 
    pthread_mutex_unlock(&queueB); 
    pthread_mutex_unlock(&countOfQueueB); 
    } 
} 

void changeCity2(int threadNumber, char city) 
{ 
    if (city == 'a') 
    { 
    while (queueInA[0] != threadNumber);// Oczekiwanie dopoki samochod nie jest 1szy w kolejce 

    pthread_mutex_lock(&bridge); 
    removeFromQueue(city, threadNumber); 

    printf("\nA-%d %d>>> [>> %d >>] <<<%d %d-B", inCityA, inQueueA, threadNumber, inQueueB, inCityB); 
    if (debugMode == 1) 
    { 
     pthread_mutex_lock(&queueA); 
     printQueue(city); 
     pthread_mutex_unlock(&queueA); 
    } 
    city = 'b'; 

    pthread_mutex_unlock(&bridge); 
    sleep(2); // Sleeping for simulating "working" time 

    int randomNumber = rand() % 4; 

    if (randomNumber % 2 == 0) 
    { 
     addToQueue(city, threadNumber); 
     changeCity2(threadNumber, city); 
    } 
    else 
    { 
     runIntoCity(threadNumber, city); 
    } 
    } 
    else if (city == 'b') 
    { 
    while (queueInB[0] != threadNumber); // Oczekiwanie dopoki samochod nie jest 1szy w kolejce  

    pthread_mutex_lock(&bridge); 


    removeFromQueue(city, threadNumber); 


    printf("\nA-%d %d>>> [<< %d <<] <<<%d %d-B", inCityA, inQueueA, threadNumber, inQueueB, inCityB); 
    if (debugMode == 1) 
    { 
     pthread_mutex_lock(&queueB); 
     printQueue(city); 
     pthread_mutex_unlock(&queueB); 
    } 
    city = 'a'; 


    pthread_mutex_unlock(&bridge); 
    sleep(2); 

    int randomNumber = rand() % 4; 

    if (randomNumber % 2 == 0) 
    { 
     addToQueue(city, threadNumber); 
     changeCity2(threadNumber, city); 
    } 
    else 
    { 
     runIntoCity(threadNumber, city); 
    } 
    } 
} 

void runIntoCity(int threadNumber, char city) 
{ 

    if (city == 'a') 
    { 
    pthread_mutex_lock(&cityA); 
    inCityA++; 
    printf("\nA-%d %d>>> [ BLANK ] <<<%d %d-B", inCityA, inQueueA, inQueueB, inCityB); 
    if (debugMode == 1) 
    { 
     pthread_mutex_lock(&queueA); 
     printQueue(city); 
     pthread_mutex_unlock(&queueA); 
    } 
    pthread_mutex_unlock(&cityA); 

    sleep(3); 

    pthread_mutex_lock(&cityA); 
    inCityA--; 
    printf("\nA-%d %d>>> [ BLANK ] <<<%d %d-B", inCityA, inQueueA, inQueueB, inCityB); 

    if (debugMode == 1) 
    { 
     pthread_mutex_lock(&queueA); 
     printQueue(city); 
     pthread_mutex_unlock(&queueA); 
    } 
    pthread_mutex_unlock(&cityA); 
    } 
    else 
    { 
    pthread_mutex_lock(&cityB); 
    inCityB++; 
    printf("\nA-%d %d>>> [ BLANK ] <<<%d %d-B", inCityA, inQueueA, inQueueB, inCityB); 

    if (debugMode == 1) 
    { 
     pthread_mutex_lock(&queueB); 
     printQueue(city); 
     pthread_mutex_unlock(&queueB); 
    } 
    pthread_mutex_unlock(&cityB); 

    sleep(3); 

    pthread_mutex_lock(&cityB); 
    inCityB--; 
    printf("\nA-%d %d>>> [ BLANK ] <<<%d %d-B", inCityA, inQueueA, inQueueB, inCityB); 
    if (debugMode == 1) 
    { 
     pthread_mutex_lock(&queueB); 
     printQueue(city); 
     pthread_mutex_unlock(&queueB); 
    } 
    pthread_mutex_unlock(&cityB); 
    } 


    addToQueue(city, threadNumber); 
    changeCity2(threadNumber, city); 
} 

void removeFromQueue(char city, int threadNumber) // Removing car from queue if its 1st in queue 
{ 
    if (city == 'a') // Car being removed from queue of city A 
    { 
    pthread_mutex_lock(&queueA); 
    pthread_mutex_lock(&countOfQueueA); 
    if (queueInA[0] == threadNumber) 
    { 

     inQueueA--; 

     int i = 1; 
     while (queueInA[i] != 0) 
     { 
      queueInA[i - 1] = queueInA[i]; 
      i++; 
     } 
     queueInA[i - 1] = 0; 
     printf("\nA-%d %d>>> [ BLANK ] <<<%d %d-B", inCityA, inQueueA, inQueueB, inCityB); 


     if (debugMode == 1) 
     { 

      printQueue(city); 
     } 
    } 
    else printf("Car is not first in queue. Error!"); 
    pthread_mutex_unlock(&queueA); 
    pthread_mutex_unlock(&countOfQueueA); 
    } 
    else if (city == 'b') 
    { 
    pthread_mutex_lock(&queueB); 
    pthread_mutex_lock(&countOfQueueB); 
    if (queueInB[0] == threadNumber) 
    { 

     inQueueB--; 

     int i = 1; 
     while (queueInB[i] != 0) 
     { 
      queueInB[i - 1] = queueInB[i]; 
      i++; 
     } 
     queueInB[i - 1] = 0; 

     printf("\nA-%d %d>>> [ BLANK ] <<<%d %d-B", inCityA, inQueueA, inQueueB, inCityB); 

     if (debugMode == 1) 
     { 
      printQueue(city); 
     } 
    } 
    else printf("Samochod nie jest pierwszy w kolejce. BLAD W KODZIE!"); 
    pthread_mutex_unlock(&queueB); 
    pthread_mutex_unlock(&countOfQueueB); 
    } 
} 



void changeCity(int threadNumber, char city) 
{ 
    if (city == 'a') 
    { 
    while (queueInA[0] != threadNumber); // Waiting until car is ready to change city - it's first in queue 

    pthread_mutex_lock(&bridge); 
    removeFromQueue(city, threadNumber); 



    printf("\nA-%d %d>>> [>> %d >>] <<<%d %d-B", inCityA, inQueueA, threadNumber, inQueueB, inCityB); 
    if (debugMode == 1) 
    { 
     pthread_mutex_lock(&queueA); 
     printQueue(city); 
     pthread_mutex_unlock(&queueA); 
    } 
    city = 'b'; 


    pthread_mutex_unlock(&bridge); 
    sleep(2); 

    int randomNumber = rand() % 4; 

    if (randomNumber % 2 == 0) 
    { 
     addToQueue(city, threadNumber); 
     changeCity2(threadNumber, city); 
    } 
    else 
    { 
     runIntoCity(threadNumber, city); 
    } 
    } 
    else if (city == 'b') 
    { 
    while (queueInB[0] != threadNumber); // Waiting until car is ready to change city - it's first in queue 

    pthread_mutex_lock(&bridge); 


    removeFromQueue(city, threadNumber); 


    printf("\nA-%d %d>>> [<< %d <<] <<<%d %d-B", inCityA, inQueueA, threadNumber, inQueueB, inCityB); 
    if (debugMode == 1) 
    { 
     pthread_mutex_lock(&queueB); 

     printQueue(city); 
     pthread_mutex_unlock(&queueB); 
    } 
    city = 'a'; 


    pthread_mutex_unlock(&bridge); 
    sleep(2); 

    int randomNumber = rand() % 4; 

    if (randomNumber % 2 == 0) 
    { 
     addToQueue(city, threadNumber); 
     changeCity2(threadNumber, city); 
    } 
    else 
    { 
     runIntoCity(threadNumber, city); 
    } 
    } 
} 

char cityDraw() // Being used at start of thread to attach threads to cities 
{ 
    int randomNumber = rand() % 100; 
    int randomNumber2 = rand() % randomNumber; 

    if (randomNumber2 % 2 == 0) 
    { 
    return 'a'; 
    } 
    else 
    { 
    return 'b'; 
    } 
} 

void *threadInitiate(int threadNumber) 
{ 
    char city = cityDraw(); 
    addToQueue(city, threadNumber); 
    while (inQueueA + inQueueB < numberOfCars); // Waiting for all threads to get run by pthread_create 
    changeCity(threadNumber, city); 
} 

void createThreads() 
{ 
    pthread_t car[numberOfCars]; 
    int i; 
    for (i = 0; i < numberOfCars; i++) 
    { 
    int wynik = pthread_create(&car[i], NULL, &threadInitiate, (void *)i + 1); //!!!!!!!!!!!!! 
    if (wynik != 0) printf("Pthread_create failed\n"); 
    else createdThreads++; 
    } 

    for (i = 0; i < numberOfCars; i++) 
    { 
    pthread_join(car[i], NULL); 
    } 
} 

void initiateQueues() // Making every elem. of queues became 0. Just to be sure. Thread numbers are starting from number 1. 
{ 
    int i; 
    for (i = 0; i<numberOfCars; i++) 
    { 
    queueInA[i] = 0; 
    queueInB[i] = 0; 
    } 
} 

int checkNumberOfCars(char *arg) // Parsing and converting to int, numer of cars from parameter 
{ 
    int argSize = 1; 
    while (arg[argSize] != '\0') 
    { 
    argSize++; 
    } 

    char temp[argSize]; 
    int indArg = 1; 
    int indTemp = 0; 
    for (indArg = 1; indArg<argSize; indArg++) 
    { 
    temp[indTemp] = arg[indArg]; 
    indTemp++; 
    } 
    temp[indTemp] = '\0'; 

    int ls = atoi(temp); 
    return ls; 
} 

int debugCheck(int argc, char **argv) // Checking if -debug parameter is given 
{ 
    if (argc>2) 
    { 
    if (strcmp(argv[2], "-debug") == 0) 
     return true; 
    else 
     return false; 
    } 
} 

int main(int argc, char **argv) 
{ 
    numberOfCars = checkNumberOfCars(argv[1]); 
    printf("\nNumber of cars from param = %d", numberOfCars); 
    debugMode = debugCheck(argc, argv); 
    if (debugMode == 1) printf("\nDebugMode is ON - writing queues status on every change"); 
    int queueArrayA[numberOfCars]; 
    int queueArrayB[numberOfCars]; 
    queueInA = queueArrayA; 
    queueInB = queueArrayB; 
    initiateQueues(); 

    pthread_mutex_init(&bridge, NULL); 
    pthread_mutex_init(&queueA, NULL); 
    pthread_mutex_init(&queueB, NULL); 
    pthread_mutex_init(&cityA, NULL); 
    pthread_mutex_init(&cityB, NULL); 
    pthread_mutex_init(&countOfQueueA, NULL); 
    pthread_mutex_init(&countOfQueueB, NULL); 

    createThreads(); 

    return 0; 
} 
+2

У вас есть конкретный вопрос или проблема? Это очень широко. –

+0

О да, извините. Я думаю, что нитки не работают синхронно, например, я запустил программу с 8 потоками и имел поток с номером 34 в очереди. Не знаю, почему, и это произошло после того, как я «исправил» код. Не вернется, потому что он тоже не работает. – kondzio14

+0

Извините, мне очень нравится разнообразие, но чтение кода с неанглийскими именами переменных и функций - это то, чего вы не должны ожидать от сообщества StackOverflow. –

ответ

0

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

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

    pthread_mutex_lock(&bridge); 
    // remove car from city of origin 
    // no need for mutex, because only one car can be on the bridge at once, 
    // so only the car on the bridge will modify the car count fields in cities 
    city[i].cars--; 
    sleep(/* some time */); 
    // add car to destination city 
    city[1-i].cars++; 
    pthread_mutex_unlock(&bridge); 
    sleep(/* some time */); 
    
  2. нити автомобиль будет работать вечно, но они будут продолжать называть все больше и больше функций рекурсивно. Это в конечном итоге взорвет стек. Напишите функцию потока автомобиля как явный бесконечный цикл. Никакой физический компьютер не позволит вам иметь график вызовов бесконечной глубины.
  3. Тонны дублированного кода. Все написано дважды, один раз для города «а» и второй раз для города «б». Используйте массивы и присвойте число 0 одному городу и 1 другому, чтобы вы могли сделать что-то вроде city[1-i].car_count++.
  4. Код, который управляет структурой данных очереди (например, находит пустое место, удаляет автомобиль из очереди и т. Д.) Смешивается с другим несвязанным кодом. Если вам действительно нужны эти очереди, в чем я сомневаюсь, напишите struct car_queue и операции, которые добавляют и удаляют автомобиль, вместо того, чтобы записывать операции очереди непосредственно в функции changeCity2, addToQueue и так далее.
  5. Ненужные мьютексы. Например, countofQueueA и queueA следует объединить в один мьютекс. На самом деле, вероятно, должно быть только три мьютекса: для города A, для города B и для моста. Это можно сделать даже с одним мьютексом для моста.
  6. Почему вы делаете rand() % 4 и сразу после этого % 2? Это не имеет никакого смысла, сразу же сделайте rand() % 2.
  7. Двойная рандомизация в cityDraw совершенно бессмысленна и дает вам слегка предвзятый результат. Например, если вы получите 0 в первой строке, вы получите либо 0, 1, либо 2 во второй строке, так что будет шанс 2/3, что автомобиль пойдет в город A. Если вы получите 0 в первом line, автомобиль отправится в город A, независимо от того, что вы получите во втором. Просто сделайте rand() % 2.
  8. Никогда не делайте что-то вроде #define true 1 - это только что представило бесплатные несовместимости с C++. Вместо этого используйте #include <stdlib.h> и напишите TRUE и FALSE.
+0

Спасибо :) очень полезно. Удаленные очереди, переписаны некоторые функции, и он работает. – kondzio14

Смежные вопросы