对于OS类,我当前必须在linux内核中创建一个线程安全队列,并使用系统调用进行交互。
现在对于关键部分,我的直觉是我想要使用mutex_lock
标题中的mutex_unlock
和mutex.h
函数。但是,我被告知我可以在down_interruptible
标题中使用up
和semaphore.h
的二进制信号量,并且它会更好。
我已阅读Difference between binary semaphore and mutex:从中我了解到互斥锁的主要优势在于它强制执行所有权的强度,以及信号量的优势在于,因为它不会强制执行所有权可以将它用作两个(多个?)不同线程之间的同步机制。
我的问题是二进制信号量的优点是什么,如果你以与互斥量完全相同的方式使用它。如果我写的话更明确:
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;
}
答案 0 :(得分:11)
在没有经验证据的情况下,我引用了 Linux内核开发
一书它(即互斥体)的行为类似于计数为1的信号量,但它有一个 更简单的界面,更高效的性能和额外的 对其使用的限制。
此外,有许多限制适用于互斥锁,但不适用于信号量。像过程这样的东西在拿着互斥锁时无法退出。此外,如果启用了{{1}}内核选项,则通过调试检查可以确保适用于互斥锁的所有约束。
因此,除非有充分的理由不使用互斥锁,否则这应该是首选。
答案 1 :(得分:5)
默认锁定原语是自旋锁。只有在你拿着锁的时候需要睡觉时,互斥锁才有意义,你在上述代码示例中肯定没有。
@Assert\File
为什么?
#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) {
为什么要初始化这些她,为什么要将指针设置为0而不是NULL?
long res = 0;
Message *msg = 0;
return语句应该在下一行。另请注意,如果类型以无符号开头,则此条件不相关。
if (len < 0) return EINVAL;
为什么不是sizeof(* msg)
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;