【问题标题】:Semaphore.WaitOne() never returns true, despire avaiablilitiesSemaphore.WaitOne() 永远不会返回 true,渴望可用性
【发布时间】:2020-02-27 04:13:27
【问题描述】:

我正在使用信号量和线程来尝试管理我正在开发的体素游戏的块加载。我的一般设置是我有一个队列管理器作业,它创建一个信号量和等待它的子作业。我已经按照所有示例进行了操作,但我无法弄清楚为什么当我在子作业的信号量上调用 WaitOne() 时,除了主线程之外,代码永远不会继续用于任何线程。

代码: 这是队列管理器作业的构造函数:

  /// <summary>
  /// Create a new job, linked to the level
  /// </summary>
  /// <param name="level"></param>
  protected QueueManagerJob(int maxChildJobsCount = 10) {
    queue = new List<QueueObjectType>();
    runningChildJobs = new Dictionary<QueueObjectType, IThreadedJob>();
    childJobResourcePool = new Semaphore(maxChildJobsCount, maxChildJobsCount);
  }

这是队列管理器作业在其队列上运行的函数:

  /// <summary>
  /// The threaded function to run
  /// </summary>
  protected override void jobFunction() {
    // This job will continue until all queue'd chunks are loaded
    while (queue.Count > 0) {
      queue.RemoveAll((queueObject) => {
        // if the chunk is already being loaded by a job
        if (runningChildJobs.ContainsKey(queueObject)) {
          IThreadedJob chunkLoaderJob = runningChildJobs[queueObject];

          // if it's done, remove it from the running jobs and remove it from the queue
          if (chunkLoaderJob.isDone) {
            runningChildJobs.Remove(queueObject);
            return true;
          }

          // if it's not done yet, don't remove it
          return false;
          // if it's not being loaded yet by a job, and we have an open spot for a new job, start and add it
        } else {
          IThreadedJob chunkLoaderJob = getChildJob(queueObject);
          runningChildJobs[queueObject] = chunkLoaderJob;
          runningChildJobs[queueObject].start();

          // don't remove the running job from the queue yet
          return false;
        }
      });
    }
  }

这是子作业的大部分:

    /// <summary>
    /// Threaded function, serializes this chunks block data and removes it from the level
    /// </summary>
    protected override void jobFunction() {
      // wait until we have a resouces, or the job is canceled.
      if (parentResourcePool.WaitOne(-1, isCanceled)) {
        doWork();

        parentResourcePool.Release();
        // if the job is canceled, abort after releasing the resource
      } else {
        abort();
      }
    }
  }

这就是它停止运行的地方。每个线程都停在

if (parentResourcePool.WaitOne(-1, isCanceled)) {

an 似乎不再继续。 它们最终在调试器中看起来像这样:

这里还有一个链接到我的基本 ThreadedJob 类,这两个类都扩展了: https://github.com/SuperMeip/MarchingCubesCSharp.A1/blob/master/Assets/Scripts/Jobs/ThreadedJob.cs

以防万一问题可能与此有关。

【问题讨论】:

  • 请不要将您的代码发布为图片。
  • 更新到代码

标签: c# multithreading unity3d semaphore


【解决方案1】:

我认为您并不完全了解生产者消费者模式。这可能会对您有所帮助:https://www.geeksforgeeks.org/producer-consumer-problem-using-semaphores-set-1 一旦信号量发出信号,等待信号量的工作线程将继续运行(当新项目添加到队列时,必须有人调用 parentResourcePool.Release())。

【讨论】:

  • 但是我正在使用与创建信号量相同的开放线程来启动信号量。因此:childJobResourcePool = new Semaphore(maxChildJobsCount, maxChildJobsCount); 而不是 childJobResourcePool = new Semaphore(0, maxChildJobsCount);
  • 确实如此,但模式仍然很奇怪,例如如果 doWork 抛出异常(我不知道调用的 jobFunction 是如何处理的),信号量将不会递增,因此线程下次等待时将无限期阻止。
  • 整洁,但为什么根本没有运行?如果我说的是真的,至少应该运行 10 个线程,没有一个。
  • 您确定没有将相同的信号量传递给多个对象吗?我看到 ChildQueueJob 的 ctor 将信号量作为参数。
  • 我将它传递给多个对象,这是我遵循的模式类型:infoworld.com/article/3088099/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 2016-02-08
相关资源
最近更新 更多