Для класса ОС в настоящее время мне нужно создать потокобезопасную очередь в ядре linux, с которой один взаимодействует с использованием системных вызовов.
Теперь для критических разделов мое чувство кишки состоит в том, что я хотел бы использовать функции mutex_lock
и mutex_unlock
в заголовке mutex.h
. Однако мне сказали, что вместо этого можно использовать двоичный семафор с down_interruptible
и up
в заголовке semaphore.h
и что было бы лучше.
Я прочитал Разницу между двоичным семафором и мьютексом. Из этого я понимаю, что основным преимуществом мьютекса является то, насколько сильно он обеспечивает право собственности, и что преимущество семафора заключается в том, что, поскольку он не обеспечивает права собственности, вы можете использовать его в качестве механизма синхронизации между двумя (несколькими?) различными потоками.
Мой вопрос в том, каковы преимущества двоичного семафора, если вы используете его точно так же, как и мьютекс. Явным образом, если бы я писал:
down()
/* critical */
up()
таким же образом, как я сделал бы
mutex_lock()
/* critical */
mutex_unlock()
Есть ли преимущество в производительности, потому что оно менее безопасно, чем мьютекс? Я что-то пропустил?
Вот небольшой фрагмент кода, который я хочу сделать потокобезопасным, если вы хотите больше контекста (это мой первый C-проект):
#define MESSAGE_MAX_SIZE 512
typedef struct list_head list_node;
/* Create message struct */
typedef struct {
size_t size;
list_node node;
char data[MESSAGE_MAX_SIZE];
} Message;
/* Create the linked list queue with dummy head */
struct {
size_t size;
list_node head;
} my_q = { 0, LIST_HEAD_INIT(my_q.head) };
/*
Adds a new item to the tail of the queue.
@data: pointer to data to add to list
@len: size of the data
*/
asmlinkage long sys_enqueue(const void __user *data, long len) {
long res = 0;
Message *msg = 0;
if (len < 0) return EINVAL;
if (len > MESSAGE_MAX_SIZE) return E2BIG;
msg = kmalloc(sizeof(Message), GFP_KERNEL);
if (msg == 0) return ENOMEM;
res = copy_from_user(msg->data, data, len);
if (res != 0) return EFAULT;
/* Start Critical Section */
my_q.size++;
list_add_tail(&msg->node, &my_q.head);
/* End Critical Section */
return 0;
}