首页 > 解决方案 > C中的缓冲区互斥锁和条件变量

问题描述

我才刚开始用 C 语言编写多线程,对如何实现它还没有完全理解。我正在编写一个读取输入文件并放入缓冲区结构数组的代码。当缓冲区没有更多可用空间时,request_t被阻塞等待可用空间。它由线程控制Lift_R。其他线程提升 1-3 操作lift()并将缓冲区中的内容写入输出文件,具体取决于int sec. secsize通过命令行给定值。这将为请求释放空间以继续读取输入。

有人可以帮助我如何正确实现这些功能。我知道还有其他与此相关的问题,但我希望我的代码满足特定条件。

(注意:lift 在 FIFO 中运行,线程使用互斥)

这是我到目前为止写的,我还没有实现任何等待条件或 FIFO,我目前专注于写入文件和调试,很快就会等待和发出信号。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> 
#include "list.h"
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; //declare thread conditions
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //declare mutex
int sec; //time required by each lift to serve a request
int size; //buffer size
buffer_t A[];
write_t write;
void *lift(void *vargp)

{
    pthread_mutex_lock(&lock);
    FILE* out;
    out = fopen("sim_output.txt", "w");
    //gather information to print
    if (write.p == NULL) //only for when system begins
    {
        write.p = A[1].from;
    }
    write.rf = A[1].from;
    write.rt = A[1].to;
    write.m = (write.p - A[1].from) + (A[1].to - A[1].from);
    if (write.total_r == NULL) //for when the system first begins
    {
        write.total_r = 0;
    }
    else
    {
        write.total_r++;
    }
    if (write.total_m == NULL)
    {
        write.total_m = write.m;
    }
    else
    {
        write.total_m = write.total_m + write.m;
    }
    write.c = A[1].to;
    //Now write the information
    fprintf(out, "Previous position: Floor %d\n", write.p);
    fprintf(out, "Request: Floor %d to Floor %d\n", write.rf, write.rt);
    fprintf(out, "Detail operations:\n");
    fprintf(out, "    Go from Floor %d to Floor %d\n", write.p, write.rf);
    fprintf(out, "    Go from Floor %d to Floor %d\n", write.rf, write.rt);
    fprintf(out, "    #movement for this request: %d\n", write.m);
    fprintf(out, "    #request: %d\n", write.total_r);
    fprintf(out, "    Total #movement: %d\n", write.total_m);
    fprintf(out, "Current Position: Floor %d\n", write.c);
    write.p = write.c; //for next statement
    pthread_mutex_unlock(&lock);
    return NULL;
}


void *request_t(void *vargp)
{
    pthread_mutex_lock(&lock); //Now only request can operate
    FILE* f;
    FILE* f2;
    f = fopen("sim_input.txt", "r");
    if (f == NULL)
    {
        printf("input file empty\n");
        exit(EXIT_FAILURE);
    }
    f2 = fopen("sim_output.txt", "w");

    int i = 0;
    for (i; i < size; i++)
    {
        //read the input line by line and into the buffer
        fscanf(f, "%d %d", &A[i].from, &A[i].to);\
        //Print buffer information to sim_output
        fprintf(f2, "----------------------------\n");
        fprintf(f2, "New Lift Request from Floor %d to Floor %d \n", A[i].from, A[i].to);
        fprintf(f2, "Request No %d \n", i);
        fprintf(f2, "----------------------------\n");
    }
    printf("Buffer is full");
    fclose(f);
    fclose(f2);
    pthread_mutex_unlock(&lock);
    return NULL;
}


void main(int argc, char *argv[]) // to avoid segmentation fault
{
    size = atoi(argv[0]);
    if (!(size >= 1))
    {
        printf("buffer size too small\n");
        exit(0);
    }
    else
    {
        A[size].from = NULL;
        A[size].to = NULL;
    }
    sec = atoi(argv[1]);
    pthread_t Lift_R, lift_1, lift_2, lift_3;

    pthread_create(&Lift_R, NULL, request_t, NULL);

    pthread_join(Lift_R, NULL);

    pthread_create(&lift_1, NULL, lift, NULL);

    pthread_join(lift_1, NULL);

    pthread_create(&lift_2, NULL, lift, NULL);

    pthread_join(lift_2, NULL);

    pthread_create(&lift_3, NULL, lift, NULL);

    pthread_join(lift_3, NULL);

}

这是结构文件:

#include <stdbool.h>

typedef struct Buffer
{
    int from;
    int to;
}buffer_t; //buffer arrary to store from and to values from sim_input

typedef struct Output
{
    int l; //lift number
    int p; //previous floor
    int rf; //request from
    int rt; //request to
    int total_m; //total movement
    int c; // current position
    int m; //movement
    int total_r; //total requests made
}write_t;

标签: cmultithreadingpthreadsbuffer

解决方案


在阅读您的代码和问题之间,我看到了很大的概念差距。代码中存在一些技术问题(例如,您永远不会关闭);和一个难以遵循的顺序。

所以,这个模式:

  pthread_create(&x, ?, func, arg);
  pthread_join(x, ...);

可以替换为:

  func(arg);

所以,你真的根本不是多线程的;就好像:

void main(int argc, char *argv[]) // to avoid segmentation fault
{
    size = atoi(argv[0]);
    if (!(size >= 1))
    {
        printf("buffer size too small\n");
        exit(0);
    }
    else
    {
        A[size].from = NULL;
        A[size].to = NULL;
    }
    sec = atoi(argv[1]);

    request_t(0);
    lift(0);
    lift(0);
    lift(0);
}

而且,知道这一点,我希望您能看到以下方面的徒劳:

pthread_mutex_lock(&lock);
....
pthread_mutex_unlock(&lock);

所以,首先要重新考虑一下你在做什么。听起来您有一个升降设备,它需要接收入站请求,也许对它们进行排序,然后处理它们。很可能是“永远”。

这可能意味着一个排序队列;但是,不是按普通标准排序的。电梯在两个方向上穿过建筑物,但意味着尽量减少方向的变化。这涉及使用顺序 ( >, < ) 和当前方向遍历队列。您可能希望 request 简单地评估提升图,并确定在哪里插入新请求。电梯图将是电梯下一步去向的单向列表。并且,也许是一个规则,即列表仅在其停在给定楼层时才查询其列表。

因此,请求可以锁定图形,更改它以反映新请求,然后解锁它。

电梯可以简单地:

  while (!Lift_is_decommissioned) {
        pthread_mutex_lock(&glock);
        Destination = RemoveHead(&graph);
        pthread_mutex_unlock(&glock);
        GoTo(Destination);
  }

请求可以是:

  pthread_mutex_lock(&glock);

  NewDestination = NewEvent.floorpressed;
  NewDirection   = NewEvent.floorpressed > NewEvent.curfloor ? Up : Down;
  i = FindInsertion(&graph, NewDestination, NewDirection);
  InsertAt(&graph, i, NewDestination);

  pthread_mutex_unlock(&glock);

这可能有点令人惊讶,从电梯内按下“转到楼层”按钮和从电梯外按下“我现在要电梯”之间没有区别。

但是,通过这种分离,您可以让电梯简单地按照上面的方法进行,并且按钮的处理程序调用上面的其他伪代码。

FindInsertion() 可能有点毛茸茸......


推荐阅读