linux - Posix 线程与互斥体同步

标签 linux multithreading

我越尝试学习这个东西,我就越感到困惑,所以我愿意接受任何建议和帮助。谢谢。程序是关于窄桥(互斥体)和在其上运行的汽车(进程)的,但一次只有一个进程可以穿过它。穿越后,桥接线程可以将自己添加到队列中,或者前往其休眠的城市然后添加到队列中。进程(汽车)需要运行直到程序终止。如果需要的话我可以将代码翻译成英文。编译后运行如下: ./program -n -debug n - 线程数,调试 - 打印队列,仅可选。我认为线程不能同步工作,例如我运行了 8 个线程的程序,并且队列中有编号为 34 的线程。不知道为什么,它发生在我“修复”代码之后。

/*
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;
}

最佳答案

这看起来像是并发编程类(class)的作业。这段代码存在很多问题,我认为不值得尝试找出错误,因为你不会因此得到任何分数,而且无论如何都必须重写所有内容。以下是大致按重要性排列的问题。

  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. 大量重复代码。所有内容都写两次,一次针对城市“a”,第二次针对城市“b”。利用数组并将数字 0 分配给一个城市,将 1 分配给另一个城市,这样您就可以执行类似 city[1-i].car_count++ 的操作。 .
  4. 管理队列数据结构的代码(例如查找空位、从队列中删除汽车等)与其他不相关的代码混合在一起。如果你真的需要这些队列(我对此表示怀疑),请写 struct car_queue以及添加和删除汽车的操作,而不是直接在函数中编写队列操作changeCity2 , addToQueue等等。
  5. 不必要的互斥体。例如,countofQueueAqueueA应该组合成一个互斥体。事实上,可能应该只存在三个互斥体:城市 A、城市 B 和网桥。甚至可以只用桥接的一个互斥锁来完成。
  6. 你为什么要这样做rand() % 4紧接着% 2结果呢?这没有任何意义,做rand() % 2马上。
  7. cityDraw 中的双重随机化完全没有意义,并且会给你一个稍微有偏差的结果。例如,如果您在第一行中得到 0,则在第二行中将得到 0、1 或 2,因此汽车将有 2/3 的机会前往 A 城市。如果您在第一行中得到 0,则无论第二行中得到什么,汽车都会前往 A 城市。就做rand() % 2 .
  8. 永远不要做类似 #define true 1 的事情- 这只是引入了与 C++ 的无端不兼容性。相反,使用 #include <stdlib.h>并写 TRUEFALSE .

关于linux - Posix 线程与互斥体同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27869286/

相关文章:

java - 如何实现无限线程返回数据?

c - 一个消费者和两个生产者中的任何一个

linux - 基本网络命令行 shell : how can I know if some device that don't answer to pings is alive on the LAN?

linux - 如何使用 ftrace 跟踪 linux 公平(调度程序)进程

java - 是否有用于处理 swing 应用程序中的数据库请求的框架?

c++ - 如何使一个线程 "promptly"中的内存存储在其他线程中可见?

java - 为什么要同时使用 boolean 值和 interrupt() 来指示线程终止?

regex - 在一行匹配后替换为第 N 行中存在的字符串

python - 通过python将多个文件组合成一个tar文件

linux - Grep 运行超过 x 分钟的进程计数