C 中的缓冲区互斥锁和条件变量
Buffer mutex and condition variables in C
我才刚刚开始用 C 编写多线程,对如何实现它还没有完全理解。我正在编写读取输入文件并放入缓冲区结构数组的代码。当缓冲区没有更多可用 space 时,request_t
被阻塞等待可用 space。它由线程 Lift_R
控制。其他线程提升 1-3 操作 lift()
并将缓冲区中的内容写入输出文件,具体取决于 int sec
的数量。 sec
和 size
并通过命令行给定值。这将释放 space 以请求继续读取输入。
有人可以帮助我如何正确实现这些功能。我知道还有其他与此相关的问题,但我希望我的代码满足特定条件。
(注意: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);
所以,首先要重新考虑一下您正在做的事情。听起来你有一个电梯设备需要接受入站请求,也许对它们进行排序,然后处理它们。可能 'forever'.
这可能意味着排序队列;但是,不是按普通标准排序的。电梯在两个方向上穿过建筑物,但意味着尽量减少方向的变化。这涉及使用顺序(>、<)和当前方向遍历队列。
您可能希望请求简单地评估提升图,并确定在何处插入新请求。
提升图将是一个单向列表,其中列出了下一步的提升位置。而且,也许有一个规则,即列表仅在它停在给定楼层时才查询其列表。
因此,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);
从电梯内按下 "goto floor" 按钮与从电梯外按下 "I want lift here now" 按钮之间没有区别,这可能有点令人惊讶。
但是,通过这种分离,您可以让电梯简单地遵循上面的配方,并且按钮的处理程序调用上面的其他伪代码。
虽然 FindInsertion() 可能有点毛茸茸....
我才刚刚开始用 C 编写多线程,对如何实现它还没有完全理解。我正在编写读取输入文件并放入缓冲区结构数组的代码。当缓冲区没有更多可用 space 时,request_t
被阻塞等待可用 space。它由线程 Lift_R
控制。其他线程提升 1-3 操作 lift()
并将缓冲区中的内容写入输出文件,具体取决于 int sec
的数量。 sec
和 size
并通过命令行给定值。这将释放 space 以请求继续读取输入。
有人可以帮助我如何正确实现这些功能。我知道还有其他与此相关的问题,但我希望我的代码满足特定条件。
(注意: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);
所以,首先要重新考虑一下您正在做的事情。听起来你有一个电梯设备需要接受入站请求,也许对它们进行排序,然后处理它们。可能 'forever'.
这可能意味着排序队列;但是,不是按普通标准排序的。电梯在两个方向上穿过建筑物,但意味着尽量减少方向的变化。这涉及使用顺序(>、<)和当前方向遍历队列。 您可能希望请求简单地评估提升图,并确定在何处插入新请求。 提升图将是一个单向列表,其中列出了下一步的提升位置。而且,也许有一个规则,即列表仅在它停在给定楼层时才查询其列表。
因此,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);
从电梯内按下 "goto floor" 按钮与从电梯外按下 "I want lift here now" 按钮之间没有区别,这可能有点令人惊讶。
但是,通过这种分离,您可以让电梯简单地遵循上面的配方,并且按钮的处理程序调用上面的其他伪代码。
虽然 FindInsertion() 可能有点毛茸茸....