2015-01-09 102 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

您有任何具體問題或疑問?這是非常廣泛的。 – 2015-01-09 21:14:40

+0

哦,是的,對不起。我認爲線程不同步工作,例如我運行8個線程的程序,並在隊列中有34號線程。不知道爲什麼,它發生在我「固定」的代碼之後。不會回去,因爲它也沒有工作。 – kondzio14 2015-01-09 22:05:59

+0

對不起,我非常喜歡多樣性,但是閱讀非英文變量和函數名的代碼只是你不應該期望StackOverflow社區做的事情。 – 2015-01-09 23:24:36

回答

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. 噸重複的代碼。一切都寫了兩次,一次爲城市'一',第二次爲城市'B'。使用數組並將數字0指定給一個城市,將數字1指定給另一個城市,以便您可以執行諸如city[1-i].car_count++之類的操作。
  4. 管理隊列數據結構的代碼(例如,發現一個空的空間,將隊列從隊列中移出等等)與其他不相關的代碼混合在一起。如果您確實需要這些我懷疑的隊列,請編寫一個struct car_queue以及添加和刪除汽車的操作,而不是直接在函數changeCity2addToQueue等中寫入隊列操作。
  5. 不必要的互斥。例如,countofQueueAqueueA應該合併爲一個互斥量。事實上,可能應該只有三個互斥體:A城市,B城市和橋樑。它甚至可以用一個互斥體來完成。
  6. 你爲什麼要做rand() % 4之後% 2之後的結果呢?它沒有任何意義,請立即執行rand() % 2
  7. cityDraw中的雙隨機化是完全沒有意義的,給你一個有點偏見的結果。例如,如果您在第一行中得到0,您將在第二行中獲得0,1或2,因此汽車將前往城市A的概率爲2/3。如果您在第一行得到0線路上,不管你在第二條路上會得到什麼,車子都會去A市。只要做rand() % 2
  8. 千萬不要做像#define true 1這樣的事情 - 這只是引入了與C++無關的不兼容問題。相反,請使用#include <stdlib.h>並編寫TRUEFALSE
+0

謝謝:)非常有用。刪除了隊列,重寫了一些函數並且它可以工作。 – kondzio14 2015-01-10 13:16:35