Semaphore.WaitOne () никогда не возвращает истину, не обращая внимания на возможности - PullRequest
0 голосов
/ 31 октября 2019

Я работаю с семафором и потоками, чтобы попытаться управлять загрузкой чанка для воксельной игры, над которой я работаю. Моя общая настройка: у меня есть задание администратора очередей, которое создает семафор и дочерние задания, которые его ожидают. Я следовал всем примерам, но не могу понять, почему, когда я вызываю WaitOne () для моего семафора в моих дочерних заданиях, код никогда не продолжается ни для одного потока, кроме основного.

CODE: Вот конструктор для задания администратора очередей:

  /// <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)) {

и, похоже, не продолжается дальше. Все они в конечном итоге выглядят так в отладчике:

enter image description here enter image description here

Также вот ссылка на мою базу ThreadedJobкласс, который расширяют оба этих класса: https://github.com/SuperMeip/MarchingCubesCSharp.A1/blob/master/Assets/Scripts/Jobs/ThreadedJob.cs

на всякий случай, если проблема может быть связана с этим.

1 Ответ

0 голосов
/ 31 октября 2019

Я не думаю, что вы в полной мере понимаете модель производителя. Это может вам помочь: https://www.geeksforgeeks.org/producer-consumer-problem-using-semaphores-set-1 Рабочие потоки, ожидающие семафора, продолжат работу после того, как семафору будет дан сигнал (кто-то должен вызывать parentResourcePool.Release (), когда новый элемент добавляется в очередь).

...