【发布时间】:2022-01-25 13:58:45
【问题描述】:
大家好,我正在尝试为大学做作业,但在使用条件变量和多线程时遇到了一些问题。每次我运行程序都会出现死锁。在这里我留下了我的(错误)解决方案的练习文本,我希望有人可以帮助我,谢谢。
TEXT___ 监视器分配:双缓冲 三个并发线程 P1、P2 和 C 使用共享缓冲区进行协作。线程 P1 使用一种称为 push_int 的方法连续生成一个整数并将其传输到缓冲区。线程 P2 连续产生一对整数,并使用一种称为 push_pair 的方法将它们传送到缓冲区。线程 C 使用一种称为 fetch 的方法不断地从缓冲区中获取一个值。缓冲区有两个槽,最初是空的。
这些方法应该如下工作: push_int 在缓冲区的任何空槽中写入一个数字。如果缓冲区已满,则 push_int 阻塞调用线程,直到有一个空槽;但是,如果另一个线程正在等待使用 push_pair 将一对数字写入缓冲区,则 push_int 会阻塞调用线程,直到不仅有一个空槽,而且 push_pair 上没有其他线程阻塞; push_pair 在缓冲区中写入一对数字。如果一个或多个缓冲区槽已满,则 push_pair 阻塞调用线程,直到缓冲区完全为空; fetch 返回缓冲区中存在的两个数字之一(无论哪个都没有关系),并将相应的插槽标记为空;如果缓冲区完全为空,则 fetch 返回 0,而不会阻塞调用线程。 分析问题。设计、实现和测试一个提供 push_int(int)、push_pair(int, int) 和 fetch() 方法的监视器。一定要避免死锁以及任何竞争条件(换句话说,缓冲区必须正常工作)。此外,应该保留并发性:线程应该尽可能并发进行,而不是不必要地阻塞。
将您的工作源代码作为一个或多个 .c/.h 文件提交,并将您的项目作为单个 .pdf 或 .txt 文档提交。或者,您可以将所有内容作为单个 .zip 包一起提交。不要提交可执行文件。项目文件应包含您对监视器的设计,您可以在其中简要解释实施背后的总体思路。如果您愿意,可以添加您认为相关和值得注意的任何内容。
只要设计是您自己的,您就可以从常用模板开始并重用您希望的任何代码部分。 __我的解决方案
/*
============================================================================
Name : monitor-template.c
Author :
Version : Dec 24, 2021
Copyright : Use as you wish
Description : Template for the implementation of a monitor and its animation
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
// CONSTANTS AND MACROS
#define N_THREADS 3
#define N_SLOTS 2
#define Empty 1 //True = Empty slot
#define Full 0 //False = FUll slot
#define FOREVER for(;;)
// DEFINITIONS OF NEW DATA TYPES
typedef char thread_name_t[10];
typedef struct {
pthread_mutex_t m;
pthread_cond_t cv;
int BUFFER[N_SLOTS];
int n_w;
int slots[N_SLOTS];
} monitor_t;
// GLOBAL VARIABLES
monitor_t mon;
// MONITOR API
void push_int(monitor_t *mon, int item);
void push_pair(monitor_t *mon, int item1, int item2);
int fetch(monitor_t *mon);
void monitor_init(monitor_t *mon);
void monitor_destroy(monitor_t *mon);
// OTHER FUNCTION DECLARATIONS
void *write_int();
void *write_pair();
void *read_buffer();
double spend_some_time(int);
// IMPLEMENTATION OF MONITOR API
void monitor_init(monitor_t *mon) {
pthread_mutex_init(&mon -> m, NULL);
pthread_cond_init(&mon -> cv, NULL);
mon -> n_w = 0;
for (int i = 0; i<N_SLOTS; i++){
mon -> BUFFER[i] = 0;
mon -> slots[i] = Empty;
}
}
void monitor_destroy(monitor_t *mon) {
pthread_cond_destroy(&mon -> cv);
pthread_mutex_destroy(&mon -> m);
}
void push_int(monitor_t *mon, int item) {
pthread_mutex_lock(&mon -> m);
mon -> n_w++;
while((mon -> slots[0] == Full) && (mon -> slots[1] == Full)){
pthread_cond_wait(&mon -> cv, &mon -> m);
}
if(mon -> slots[0] == Empty){
mon -> BUFFER[0] = item;
printf("P1 is writing: %d\n", item);
mon -> slots[0] = Full;
}
else{
mon -> BUFFER[1] = item;
printf("P1 is writing: %d\n", item);
mon -> slots[1] = Full;
}
mon -> n_w--;
pthread_mutex_unlock(&mon -> m);
}
void push_pair(monitor_t *mon, int item1, int item2) {
pthread_mutex_lock(&mon -> m);
mon -> n_w++;
while((mon -> slots[0] == Full) || (mon -> slots[1] == Full)){
pthread_cond_wait(&mon -> cv, &mon -> m);
}
printf("P2 is writing: %d %d\n", item1, item2);
mon -> BUFFER[0] = item1;
mon -> slots[0] = Full;
mon -> BUFFER[1] = item2;
mon -> slots[1] = Full;
mon -> n_w--;
pthread_mutex_unlock(&mon -> m);
}
int fetch(monitor_t *mon) {
pthread_mutex_lock(&mon -> m);
int value;
if((mon -> slots[0] == Empty) && (mon -> slots[1] == Empty)){
value = 0;
}
else{
if(mon -> slots[0] == Full){
value = mon -> BUFFER[0];
mon -> slots[0] = Empty;
}
else{
value = mon -> BUFFER[1];
mon -> slots[1] = Empty;
}
pthread_cond_signal(&mon -> cv);
//pthread_cond_signal(&mon -> cv);
}
return value;
pthread_mutex_unlock(&mon -> m);
}
// MAIN FUNCTION
int main(void) {
pthread_t P1_id, P2_id, C_id;
thread_name_t P1, P2, C;
monitor_init(&mon);
sprintf(P1,"t%d",0);
pthread_create(&P1_id, NULL, &write_int, NULL);
sprintf(P2,"t%d",1);
pthread_create(&P2_id, NULL, &write_pair, NULL);
sprintf(C,"t%d",2);
pthread_create(&C_id, NULL, &read_buffer, NULL);
pthread_join(P1_id, NULL);
pthread_join(P2_id, NULL);
pthread_join(C_id, NULL);
monitor_destroy(&mon);
return EXIT_SUCCESS;
}
// TYPE 1 THREAD LOOP
void *write_int(){
FOREVER{
spend_some_time(150);
int item = 45;
push_int(&mon, item);
}
pthread_exit(NULL);
}
void *write_pair(){
FOREVER{
spend_some_time(100);
int item1, item2;
item1 = 13;
item2 = 65;
push_pair(&mon, item1, item2);
}
pthread_exit(NULL);
}
void *read_buffer(){
FOREVER{
spend_some_time(40);
int value = fetch(&mon);
if(value == 0){
printf("Empty buffer\n");
}
else{
printf("Read value: %d\n", value);
}
}
pthread_exit(NULL);
}
// AUXILIARY FUNCTIONS
double spend_some_time(int max_steps) {
double x, sum=0.0, step;
long i, N_STEPS=rand()%(max_steps*1000000);
step = 1/(double)N_STEPS;
for(i=0; i<N_STEPS; i++) {
x = (i+0.5)*step;
sum+=4.0/(1.0+x*x);
}
return step*sum;
}
【问题讨论】:
-
欢迎来到 Stack Overflow。请阅读the help pages,接受SO tour,阅读How to Ask,以及this question checklist。最后请学习如何创建minimal reproducible example,重点是minimal部分。
标签: c multithreading mutex condition-variable