Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 什么是多线程操作和不操作?_Multithreading_Language Agnostic - Fatal编程技术网

Multithreading 什么是多线程操作和不操作?

Multithreading 什么是多线程操作和不操作?,multithreading,language-agnostic,Multithreading,Language Agnostic,我正在将我新发现的线程知识应用到任何地方,并获得了许多惊喜 示例: 我使用线程在 数组。结果每一天都不一样 时间问题是我所有的 线程正在更新相同的 变量和未同步 哪些是已知的线程问题 使用时应注意什么 线程 什么是好的多线程资源 请举例说明 旁注:(我将我的程序thread\u add.java重命名为thread\u random\u number\u generator.java:-)在多线程环境中,您必须注意同步,这样两个线程不会通过同时执行修改来破坏状态。否则,您可以在代码中设置竞态

我正在将我新发现的线程知识应用到任何地方,并获得了许多惊喜

示例:

我使用线程在 数组。结果每一天都不一样 时间问题是我所有的 线程正在更新相同的 变量和未同步

  • 哪些是已知的线程问题
  • 使用时应注意什么 线程
  • 什么是好的多线程资源
  • 请举例说明

旁注:
(我将我的程序
thread\u add.java
重命名为
thread\u random\u number\u generator.java
:-)

在多线程环境中,您必须注意同步,这样两个线程不会通过同时执行修改来破坏状态。否则,您可以在代码中设置竞态条件(例如,请参见)。您还必须调度线程以执行各种任务。然后,您必须确保同步和调度不会导致死锁,多个线程将无限期地相互等待

同步

像增加计数器这样简单的操作需要同步:

counter += 1;
假设以下事件序列:

  • 计数器
    初始化为0
  • 线程A将
    计数器
    从内存检索到cpu(0)
  • 上下文切换
  • 线程B将
    计数器
    从内存检索到cpu(0)
  • 线程B增加cpu上的计数器
  • 线程B将
    计数器
    从cpu写回内存(1)
  • 上下文切换
  • 线程A增加cpu上的计数器
  • 线程A将
    计数器
    从cpu写回内存(1)
此时,
计数器
为1,但两个线程都试图增加它。对计数器的访问必须通过某种锁定机制进行同步:

lock (myLock) {
  counter += 1;
}
只允许一个线程在锁定块内执行代码。执行此代码的两个线程可能会导致以下事件序列:

  • 计数器已初始化为0
  • 线程A获取
    myLock
  • 上下文切换
  • 线程B试图获取
    myLock
    ,但必须等待
  • 上下文切换
  • 线程A将
    计数器
    从内存检索到cpu(0)
  • 线程A增加cpu上的计数器
  • 线程A将
    计数器
    从cpu写回内存(1)
  • 线程A释放myLock
  • 上下文切换
  • 线程B获取
    myLock
  • 线程B将
    计数器
    从内存检索到cpu(1)
  • 线程B增加cpu上的计数器
  • 线程B将
    计数器
    从cpu写回内存(2)
  • 线程B释放myLock
此时,
计数器
为2

日程安排

调度是另一种同步形式,您必须使用事件、信号量、消息传递等线程同步机制来启动和停止线程。下面是C#中的一个简化示例:

您会注意到,对
this.task
的访问可能没有正确同步,工作线程无法将结果返回主线程,并且无法向工作线程发出终止的信号。所有这些都可以在一个更详细的例子中得到纠正

死锁

死锁的一个常见示例是,当您有两个锁,并且不小心获取它们时。在某一点上,您在
lock2
之前获得
lock1

public void f() {
  lock (lock1) {
    lock (lock2) {
      // Do something
    }
  }
}
在另一点上,您在
lock1
之前获取
lock2

public void g() {
  lock (lock2) {
    lock (lock1) {
      // Do something else
    }
  }
}
让我们看看这会如何死锁:

  • 线程A调用
    f
  • 线程A获取
    lock1
  • 上下文切换
  • 线程B调用
    g
  • 线程B获取
    lock2
  • 线程B试图获取
    lock1
    ,但必须等待
  • 上下文切换
  • 线程A试图获取锁2,但必须等待
  • 上下文切换

此时,线程A和线程B正在互相等待并处于死锁状态。

在.Net中,当我开始尝试进入多线程时,有一件事让我感到惊讶,那就是除了创建UI控件的线程之外,您无法直接从任何线程更新UI控件

有一种方法可以解决这个问题,那就是使用Control.Invoke方法来更新另一个线程上的控件,但是第一次不是100%明显


要记住的最重要的事情是:你真的需要多线程吗?

需要注意的一件重要事情(使用多核和CPU)是。

除了向你指出谷歌,我不能给你举其他例子。搜索线程基础,线程同步,你会得到比你知道更多的点击率

线程的基本问题是线程彼此不了解-因此它们会很高兴地踩在彼此的脚趾上,就像两个人试图通过一扇门一样,有时它们会一个接一个地通过,但有时它们都试图同时通过,并且会被卡住。这很难重现,很难调试,有时还会引起问题。如果您有线程并看到“随机”故障,这可能就是问题所在

因此,需要注意共享资源。如果你和你的朋友想要一杯咖啡,但是只有一个勺子,你不能同时使用它,你们中的一个将不得不等待另一个。用于“同步”访问共享勺子的技术是锁定。你
public void g() {
  lock (lock2) {
    lock (lock1) {
      // Do something else
    }
  }
}