nachos操作系统(四)

本文详细探讨了使用锁和条件变量实现线程间互斥的方法,通过具体代码示例,分析了不同错误类型对线程行为的影响,以及如何通过设置错误类型参数来模拟并观察线程在遇到错误时的挂起行为。

今天用锁+条件变量实现互斥。

但是怎么用呢?

重新说明一下,当系统开始运行后,它首先执行thread中的main函数,然后,main函数第一个参数是一个数字,第二个参数是一个字符串,二维的不知道是为什么。

q是设置testnum,测试哪个函数
t是设置threadnum(线程数),
n就是设置n(节点个数),
e是设置err_type(错误类型),
有一个default,还是设置testnum。
然后就进入了threadtest函数。

还有参数设置z,x,c什么的,不过就没有什么关系了,下面的都需要特定的参数触发才行。

转到threadtest函数,就简单了,第一个test应该是一个默认简单线程作为一个案例。

第二个test创建了一个dllist,就是我写的一个双向链表,然后创建了n个进程,全部fork在dllistthread,是一个函数,应该就是说,这个线程只运行这个函数,然后又执行这个函数是什么意思呢?它是开了几个线程,然后,它应该只存取一次而已,试一下命令:
./nachos -q 2 -t 2 -n 2
它的意思是,设置了两个线程,设置了两个节点。也就是说,一个线程就弄两个节点?试一下
出来的结果为:
Thread 2 : inserted key=43
Thread 2 : inserted key=46
Thread 2 : removed key=43
Thread 2 : removed key=46
Thread 1 : inserted key=43
Thread 1 : inserted key=46
Thread 1 : removed key=43
Thread 1 : removed key=46
No threads ready or runnable, and no pending interrupts.
Assuming the program completed.
Machine halting!
令人意外的是,它永远不会出错,它就是依次执行的,并没有并发的现象,如果让它出错,就要在后面添加上-e,为什么要如此,那就要看为什么e会行,看看sortinsert,它里面就一个地方用到了err,那么,关键代码:

void DLList::SortedInsert(void *item, int sortKey) // routines to put/get items on/off list {
    DLLElement *insertItem = new DLLElement(item, sortKey); // 新建一个节点
    DLLElement *ptr = first; // 代表头节点指针
    if (IsEmpty()) { // 如果是空的,这个就是头节点
        first = insertItem;
        if (err_type == 2) { // 如果是第二号错误
            printf("SortedInsert error,first!=last\n"); // 插入错误,因为是空的?头尾不能相等
            currentThread->Yield(); // 挂起
        }
        last = insertItem; // 这是一个双向链表指针
    }
    else { // 如果不空,就进行查找插入
        for (; ptr != NULL; ptr = ptr->next)
            if (ptr->key > sortKey)
                break; // 找到大于它的哪个位置了,中断
        if (err_type == 3) { // 这里又出现了一个错误,为什么呢?一定会往下走啊?
            printf("SortedInsert error,the postion lost\n");
            currentThread->Yield();
        }
        if (ptr == NULL) { // 如果没有找到,就是为空了,那么此值应该是最大的了
            insertItem->prev = last; // 那么它就是尾节点
            last->next = insertItem; // 就这样连接起来
            last = insertItem; // 转换last位置
            last->next = NULL;
        }
        else if (ptr == first) { // 如果第一个就大于
            insertItem->next = first; // 那么它就是头节点。。。
            first->prev = insertItem;
            first = insertItem; // 转换first位置
            first->prev = NULL; // 它是一个双向链表,而并没有说它是一个循环链表
        }
        else { // 那么就是在中间的
            ptr->prev->next = insertItem;
            insertItem->prev = ptr->prev; // 就是普通插入
            if (err_type == 4) { // 不知道为嘛它又有错误了,它不允许在中间插入?
                printf("SorteadInsert error,sort error\n");
                currentThread->Yield();
            }
            insertItem->next = ptr;
            ptr->prev = insertItem; // 就是普通插入啊?
        }
    }
}
void *DLList::SortedRemove(int sortKey) { // remove first item with key==sortKey   
                                   // return NULL if no such item exists,在插入中没有出错提示
DLLElement *ptr = first; 
    if (IsEmpty()) 
        return NULL; 
    for (; ptr != NULL; ptr = ptr->next) 
        if (ptr->key > sortKey) 
            break; 
    if (ptr == NULL) { 
        printf("Remove error!No such a key!"); 
        return NULL; 
    } 
    else if (ptr == first) { 
        first = first->next; 
        first->prev = NULL; 
    } 
    else if (ptr == last) { 
        last = last->prev; 
        last->next = NULL; 
    } 
    else { 
        ptr->prev->next = ptr->next; 
        ptr->next->prev = ptr->prev; 
    } 
    return ptr->item; 
}

那么,是否有地方能够改动这个err呢?err是私有的,外部不可改动它。

这个错误是啥意思呢,就是一旦不能插入,它就挂起来了,而不是说它,emmm,真的就错了,

现在总结一下:
第一个错误是不为空并且只要移除就挂起
第二个错误是为空的时候不能插入
第三个错误是不为空时不能插入
第四个错误是不为空且它在中间的时候不能插入
以上全部挂起,真的是奇怪。。。。

运行的时候,它会先执行最后一个,然后依次执行,挂起后,后面还会执行,但是只要执行,就会出错。

也就是说,线程的顺序,是我们指定好的。在所有线程被挂起后,肯定会唤醒某一个线程,但是唤醒哪一个线程。

好好看看,emmmm,thread2先进行插入,它会插入两次,删除两次,currentThread->Yield()是进行强制进程切换,它应该是依次切换的,代码本身没问题,是它的挂起没有说明白,不是remove error,而是hanging

Thread 2 : inserted key=42
Thread 2 : inserted key=72
test Thread 2 reomved
Remove error // 线程2挂起
Thread 1 : inserted key=42 // 线程1开始
Thread 1 : inserted key=72
test Thread 1 reomved
Remove error // 线程1第一次remove的第一个错
Remove errorr // 线程2的第一次remove的第二个错
Remove errorr // 线程1的第一次remove的第二个错
Thread 2 : removed key=42 // 线程2的第二次remove
test Thread 2 reomved
Remove error // 线程二的第二次remove的第一个错
// 下面进行线程1的第二次remove的第一个错
段错误 (核心已转储)
这个判断真的是太难了。完全没有可控性。

它实现了这么几种错误,而且用几个err参数就能重现这些错误,着实不错。








 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值