为什么变量绑定会影响循环体内的生命周期?

时间:2019-05-10 10:00:56

标签: multithreading rust mutex

chapter 20的“ The Rust Programming Language”中,您将练习构建一个简单的多线程Web服务器。在练习中,您使用单个<!-- item template --> <script type="text/x-template" id="item-template"> <li> <div :class="{bold: isFolder}" @click="toggle" @dblclick="makeFolder"> {{ item.name }} <span v-if="isFolder">[{{ isOpen ? '-' : '+' }}]</span> </div> <ul v-show="isOpen" v-if="isFolder"> <tree-item class="item" v-for="(child, index) in item.children" :key="index" :item="child" @make-folder="$emit('make-folder', $event)" @add-item="$emit('add-item', $event)" ></tree-item> <li class="add" @click="$emit('add-item', item)">+</li> </ul> </li> </script> <p>(You can double click on an item to turn it into a folder.)</p> <!-- the demo root element --> <ul id="demo"> <tree-item class="item" :item="treeData" @make-folder="makeFolder" @add-item="addItem" ></tree-item> </ul> var treeData = { name: 'My Tree', children: [ { name: 'hello' }, { name: 'wat' }, { name: 'child folder', children: [ { name: 'child folder', children: [ { name: 'hello' }, { name: 'wat' } ] }, { name: 'hello' }, { name: 'wat' }, { name: 'child folder', children: [ { name: 'hello' }, { name: 'wat' } ] } ] } ] } 频道。所有工作线程都访问单个接收器,该接收器包含以下内容:std::sync::mpsc

如果我们将工作线程编写为:

Arc<Mutex<mpsc::Receiver<Message>>>

那我们就没有实现并发性,显然工人坚持使用我认为的互斥锁,因为在上一个作业完成之前,没有工人能够拉出另一个作业。但是,如果我们只是简单地将其更改为(书中显示代码的方式):

let thread = thread::spawn(move || loop {
    match receiver.lock().unwrap().recv().unwrap() {
        Message::NewJob(job) => {
            println!("Worker {} got a job; executing.", id);

            job.call_box();

            println!("Worker {} job complete.", id);
        }
        Message::Terminate => {
            println!("Worker {} was told to terminate.", id);

            break;
        }
    };
    println!("hello, loop");
});

然后一切正常。如果触发5个请求,您将看到每个线程立即获得一个。并发!

问题是“为什么变量绑定会影响生存期”(我假设是原因)。否则,我会丢失什么,那又是什么?该书本身讨论了由于锁定范围的原因,如何无法使用let thread = thread::spawn(move || loop { let message = receiver.lock().unwrap().recv().unwrap(); match message { Message::NewJob(job) => { println!("Worker {} got a job; executing.", id); job.call_box(); println!("Worker {} job complete.", id); } Message::Terminate => { println!("Worker {} was told to terminate.", id); break; } }; println!("hello, loop"); }); 实现worker循环,但显然甚至在内部循环中也有龙。

1 个答案:

答案 0 :(得分:2)

因为在Rust中,"resource acquisition is initialization"

具体来说,receiver.lock()返回一种类型,该类型在初始化时获取锁,而在删除时释放锁。

在您的第一个示例中,MutexGuard的生存期延长到match语句的末尾,因此将在调用job.call_box()时保持锁定。

match receiver.lock().unwrap().recv().unwrap() {
    // ...
};
// `MutexGuard` is dropped and lock is released here

在第二个示例中,锁保护仅保持足够长的时间才能从您的消息队列中读取消息;在语句的末尾放下了锁卫,并在输入match之前释放了锁。

let message = receiver.lock().unwrap().recv().unwrap();
// `MutexGuard` is dropped and lock is released here

match message {