c - C中的缓冲区互斥锁和条件变量
问题描述
我才刚开始用 C 语言编写多线程,对如何实现它还没有完全理解。我正在编写一个读取输入文件并放入缓冲区结构数组的代码。当缓冲区没有更多可用空间时,request_t
被阻塞等待可用空间。它由线程控制Lift_R
。其他线程提升 1-3 操作lift()
并将缓冲区中的内容写入输出文件,具体取决于int sec
. sec
并size
通过命令行给定值。这将为请求释放空间以继续读取输入。
有人可以帮助我如何正确实现这些功能。我知道还有其他与此相关的问题,但我希望我的代码满足特定条件。
(注意: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;
解决方案
在阅读您的代码和问题之间,我看到了很大的概念差距。代码中存在一些技术问题(例如,您永远不会关闭);和一个难以遵循的顺序。
所以,这个模式:
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() 可能有点毛茸茸......
推荐阅读
- python - 关于在 zip 文件中打开 .h5 文件的问题 [python]
- python - ValueError:无法在位置解析字符串“”
- javascript - 如何在 JavaScript 中获取 24 小时的剩余时间
- javascript - 捕获完全限定域名的“主机”部分的正确方法
- docker - 从源“https://admin.example.com”访问“https://api.example.com/admin/user/login”的 XMLHttpRequest 已被 CORS 策略阻止
- kubernetes - net/http:使用 KOPS 的 TLS 握手超时
- python - Kucoin 的 Websocket
- python - LXML + python:如何更改元素的每个实例
- python-3.x - 无法在 python 中获得所需的输出
- flutter - 我怎样才能在颤振中做同样的信用风格?