我是大二的学生,现在正在学习操作系统这门课,我想通过实现二进制搜索树和使用mutex来比较细粒度和粗粒度,节点插入和删除功能使用了锁和解锁,并打印了执行时间,我认为细粒度会更快,但是,即使我改变数字,粗粒度也更快。但是,即使我改变了数字,粗粒度的速度也更快。我是不是做错了代码?
int lab2_node_insert_fg(lab2_tree *tree, lab2_node *new_node){
if (tree->root == NULL) {
tree->root = new_node;
return LAB2_ERROR;
}
if (search_key(tree,new_node->key)) {
return LAB2_ERROR;
}
lab2_node* cur = tree->root;
while (1) {
if (cur->key < new_node->key) {
if (cur->right == NULL) {
pthread_mutex_lock(&lock); // LOCK
cur->right = new_node;
pthread_mutex_unlock(&lock); // UNLOCK
return LAB2_SUCCESS;
}
cur = cur->right;
}
else {
if (cur->left == NULL) {
pthread_mutex_lock(&lock); // LOCK
cur->left = new_node;
pthread_mutex_unlock(&lock); // UNLOCK
return LAB2_SUCCESS;
}
cur = cur->left;
}
}
}
int lab2_node_insert_cg(lab2_tree *tree, lab2_node *new_node){
pthread_mutex_lock(&lock); // LOCK
if (tree->root == NULL) {
tree->root = new_node;
pthread_mutex_unlock(&lock); // UNLOCK
return LAB2_ERROR;
}
if (search_key(tree,new_node->key)) {
pthread_mutex_unlock(&lock); // UNLOCK
return LAB2_ERROR;
}
lab2_node* cur = tree->root;
while (1) {
if (cur->key < new_node->key) {
if (cur->right == NULL) {
cur->right = new_node;
pthread_mutex_unlock(&lock); // UNLOCK
return LAB2_SUCCESS;
}
cur = cur->right;
}
else {
if (cur->left == NULL) {
cur->left = new_node;
pthread_mutex_unlock(&lock); // UNLOCK
return LAB2_SUCCESS;
}
cur = cur->left;
}
}
}
我想第一个片段应该是代表细粒度的版本,另一个是粗粒度的版本。
"细粒度 "版本缺少了一个创建根节点的锁。另外,你持有分配新节点的锁,你没有这样做的条件。当你迭代树的时候,在存在并发删除的情况下,一次锁定一个节点是不够的。这些都是并发性的问题。
通常,细粒度和粗粒度锁的区别不在于你的锁部分的 "大小"(你用锁覆盖的代码量),而是指锁的粒度与数据结构本身的关系。
所以,一种方法是为整棵树配备一个锁--粗粒度锁。另一种方法是在较低层次(如每个节点)引入锁,以消除在不同树节点上并行运行的两个操作时的锁争用。这类似于数据库空间中表锁和行级锁的区别。
细化版本的一种方法是每个节点都有一个锁,并使用所谓的交手锁。对于插入操作,你必须锁定当前节点,直到你确定并锁定下一个节点,因为你的下降。
做额外的研究,对你的实现进行相应的修改,然后重新测试。
一般来说,如果访问模式倾向于打不同的锁,那么细粒度的锁定可以带来更可扩展的实现。如果大多数时候不是这种情况,那么粗粒度的版本可能会表现得一样好,或者稍微好一点,因为在整个操作过程中可以保持一个单一的锁,而不是必须获得不同的锁,其中大多数锁又会导致锁争夺。一如既往,这取决于实际的使用模式。