短: 我有一个负责与设备通信的模型。该模型有两个线程:一个用于通信(读取和写入),另一个用于记录结果。使用互斥体确保线程安全不是问题。
现在,我有了使用此模型从设备获取/发送值的主程序。假设我有一个缓冲区。主程序本身是多线程的,这意味着我需要保护多个线程之间以及与设备模型通信时的缓冲区。
对所有事情使用一个全局互斥体违反了模型原则,并且会让一切变得更加复杂。
如何在通信模型和主程序之间建立线程安全的接口?
长: 请允许我用一个简单的例子来说明这个问题。
我的设备模型结构如下:
设备.h
#ifndef DEVICE_H
#define DEVICE_H
struct d_in {
int x;
int y;
int z;
};
struct d_out {
int x;
int y;
int z;
};
struct device {
struct d_in input;
struct d_out output;
pthread_mutex_t mutex;
sem_t sem_data;
};
void *communication_thread(void *arg);
void *logging_thread(void *arg);
void _init_device();
void _read_input(struct d_in *input);
void _write_output(const struct d_out *output);
//////////////////////////////////////
void transfer_data(struct *dev) // that what I want as interface
#endif /* DEVICE_H */
设备.c
#include "device.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "special_card_for_reading_from_device_.h"
static struct device dev;
void init_device() {
dev.input.x = 0;
dev.input.y = 0;
dev.input.z = 0;
dev.output.x = 0;
dev.output.y = 0;
dev.output.z = 0;
pthread_mutex_init(&dev.mutex, NULL);
sem_init(&sem_data,NULL, NULL);
}
void read_input() {
pthread_mutex_lock(&dev.mutex);
read_fucntion(&dev.input);
pthread_mutex_unlock(&dev.mutex);
}
void write_output() {
pthread_mutex_lock(&dev.mutex);
write_fucntion(&dev.output);
pthread_mutex_unlock(&dev.mutex);
}
void *communication_thread(void *arg) {
while (1) {
read_input();
write_output();
sem_post(&sem_data);
sleep(1); // Simulating communication delay
}
return NULL;
}
void *logging_thread(void *arg) {
FILE *fp = fopen("log.txt", "w");
if (fp == NULL) {
perror("Error opening log file");
exit(EXIT_FAILURE);
}
while (1) {
sem_wait(&sem_data);
pthread_mutex_lock(&dev.mutex);
fprintf(fp, "Input: %d %d %d\n", dev.input.x, dev.input.y, dev.input.z);
fprintf(fp, "Output: %d %d %d\n\n", dev.output.x, dev.output.y, dev.output.z);
pthread_mutex_unlock(&dev.mutex);
sleep(2); // Logging interval
}
fclose(fp);
return NULL;
}
然后我就有了带有线程的主程序
transfer
void *transfer(void *arg) {
while (1) {
// how to protect this section
transfer(&buffer_dev_data);
//////////////////////////
sleep(1);
}
return NULL;
}
void *another_thread(void *arg) {
while (1) {
// how to protect this section
operations_on_bufffer(buffer_dev_data);
//////////////////////////
sleep(1);
}
return NULL;
}
使用两个互斥锁来保护同一行是否会导致死锁等问题?如果我在传输函数内部使用一个互斥锁,并在其外部使用另一个互斥锁,它最终看起来会是一样的:
mutex_lock(&mut_B);
mutex_look(&mut_A);
// critical section
mutex_unlock((&mut_A);
mutex_unlock(&mut_B);
有问题吗?
注意事项: 该程序是为具有实时内核的实时系统(RT-Linux)而设计的。它要复杂得多,并且还包括线程的优先级。然而,目前这只是附加信息。
我不同意你的说法“对所有事情都使用一个全局互斥体违反了模型原则”。
您的 struct device
中有一组易失性数据,名为
input
和 output
,只能由 one线程访问。为了避免并发访问,您需要 one 保护器 - one 互斥体。 考虑使用
PTHREAD_MUTEX_RECURSIVE
属性来允许递归锁。
还可以考虑使用 MRSW 锁(多个读取器/单个写入器),它允许从多个线程进行只读访问而不会阻塞。