首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >螺纹安全(等级和结构)

螺纹安全(等级和结构)
EN

Stack Overflow用户
提问于 2022-01-21 06:15:32
回答 3查看 618关注 0票数 1

这将是一个非常基本的问题。关于结构如何是线程安全的,类是不安全的,我有一些困惑。

以下是我认为线程安全和不安全的含义。

线程不安全--如果允许多个线程同时修改任何对象。

线程安全-如果不允许任何对象同时修改多个线程。

下面是我尝试过的结构代码:

代码语言:javascript
复制
var basket = Basket()

func threadSafetyForStruct1() {
    let queue = DispatchQueue(label: "threadSafety1", attributes: [.concurrent])
    queue.async {
        for age in 1...30 {
            basket.amount = age
        }
    }
}

func threadSafetyForStruct2() {
    let queue = DispatchQueue(label: "threadSafety2", attributes: [.concurrent])
    queue.async {
        for age in 31...60 {
            basket.amount = age
        }
    }
}

threadSafetyForStruct1()
threadSafetyForStruct2()

下面是我尝试过的类代码:

代码语言:javascript
复制
let animal = Animal()

func threadSafetyForClass1() {
    let queue = DispatchQueue(label: "threadSafety1", attributes: [.concurrent])
    queue.async {
        for age in 1...30 {
            animal.age = age
            animal.name = "name\(age)"
        }
    }
}

func threadSafetyForClass2() {
    let queue = DispatchQueue(label: "threadSafety2", attributes: [.concurrent])
    queue.async {
        for age in 31...60 {
            animal.age = age
            animal.name = "name\(age)"
        }
    }
}

threadSafetyForClass1()
threadSafetyForClass2()

这两种代码都成功运行。没有运行时错误,也没有编译时间。两者在末尾都有意想不到的值,这在我运行并发队列时是预期的。

我在这里错过了什么?

EN

回答 3

Stack Overflow用户

发布于 2022-01-21 09:10:17

线程安全是一个广泛的话题。但是,在程序执行结束时得到意外值的事实表明,代码并不是线程安全的。

这样,我相信您在使用structclass时希望得到某种不同的结果。也许是撞车之类的?既然如此,它为什么不坠毁呢?

  1. ,一种解释是,您没有修改要修改的对象中的任何引用类型。您正在修改对象中的IntString属性,这些属性是值类型。我做了一些测试,发现Swift中价值类型的分配大多是线程安全的。这样你的程序就不会崩溃。--

如果您的对象如下所示:

代码语言:javascript
复制
class Name{
    var first: String = ""
    var last: String = ""
    init(){}
}

struct Animal{
    var age: Int
    var name: Name
    init(){
        age = 0
        name = Name()
    }
}

您试着从两个线程中同时读取和分配Name的新实例--现在这有可能使程序崩溃。

在分配新值时,会得到这样的错误:

代码语言:javascript
复制
malloc: Double free of object

如果您使用的是名称的struct实现,则不会发生同样的情况。那么,这是否使struct线程比class更安全呢?更多的线程安全-是的。但是你的程序的结果仍然是不可预测的,所以它不能解决这个问题。

  1. 解释2是我在测试中观察到的。线程安全在现实世界中发挥作用,在这种情况下,数据是以任意方式访问的。

在您的代码中,您正在每个线程中执行30次读取和分配任务。在这30种操作之间没有任意复杂的代码位可以执行。

如果您要在每次操作之前引入一个人为的随机延迟(类似于usleep) (并且要专门使用class实例),那么您可能会遇到程序崩溃。

备注

我做了一个小的Git的版本,你的程序,确实设法崩溃。

https://github.com/Thisura98/ConcurrentTest

票数 1
EN

Stack Overflow用户

发布于 2022-01-21 08:21:54

首先,结构是值类型,这意味着它们通常是通过值传递的(副本是创建的)。但也不总是这样。当您在闭包中使用它们( queue.async调用中的函数)时,它会被引用捕获。因此,在这种情况下,结构和类之间没有真正的区别。

现在,仅仅因为某些东西是一个结构,并不能使它自动线程安全。线程安全是一个广泛的话题。一个通用的定义是:一个函数(或函数的集合)是线程安全的,如果当您并行执行它们时,结果就好像它们是按某种任意顺序顺序执行的一样。因此,线程的使用只是为了优化目的,它不以任何方式改变行为。

当您按值传递事物时,就会创建副本。所以不管你在副本上做什么,它都不会影响外部。从这个意义上说,事情变得线程安全,因为资源不再是共享的。但是,当通过引用传递时,您将共享资源,因此出现了线程安全问题。

总结:线程安全并不适用于数据本身(struct或class),而是应用于您访问共享数据的方式。

在末尾都有意想不到的值,这是意外的,因为我正在运行并发队列。

这完全和预期的一样。您确实有一个队列,但是由于dispatcher是并发的,所以会有多个线程使用该队列。这些线程并行运行您的内部函数。没有锁(或其他同步原语),您的代码就不是线程安全的,因为多个线程将同时访问数据。在最好的情况下,结果是交错的。在最坏的情况下,它可能会完全崩溃(除非Swift保证分配是线程安全的,这一点我不确定)。

票数 0
EN

Stack Overflow用户

发布于 2022-01-21 09:01:59

在执行for-循环时,由于上下文切换,您正在观察不一致的结果。一个循环运行一段时间,然后另一个循环运行一段时间,它们来回跳到循环结束为止。

不能保证每个循环都会在不中断其他队列的情况下开始运行到完成。

仅仅因为某物是一个结构并不意味着它是线程安全的。您必须在从不同队列访问结构的区域中保护结构。在这种情况下,您需要保护for-循环中的结构,确保您的循环在其他队列有机会跳入之前启动并完成执行。

其中一种方法是使用NSLock,但是有许多方法可以同步访问代码块。

代码语言:javascript
复制
var basket = Basket()
let basketLock = NSLock()

func threadSafetyForStruct1() {
    let queue = DispatchQueue(label: "threadSafety1", attributes: [.concurrent])
    queue.async {
        basketLock.lock()
        for age in 1...30 {
            basket.amount = age
        }
        basketLock.unlock()
    }
}

func threadSafetyForStruct2() {
    let queue = DispatchQueue(label: "threadSafety2", attributes: [.concurrent])
    queue.async {
        basketLock.lock()
        for age in 31...60 {
            basket.amount = age
        }
        basketLock.unlock()
    }
}

threadSafetyForStruct1()
threadSafetyForStruct2()

当第一个队列获得锁时,另一个队列将被阻塞,直到第一个队列释放锁为止。只有这样,第二个队列才能获得锁并执行其操作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70797142

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档