Как предотвратить непоследовательную обработку нескольких активаций диска discordrb? - PullRequest
1 голос
/ 13 апреля 2020

У меня есть бот Ruby Discord (discordrb), написанный для управления персонажами D & D. Я замечаю, что когда несколько игроков подают одну и ту же команду одновременно, результаты, которые они получают, не являются независимыми. Запрос одного игрока (назначение оружия его персонажу) заканчивается назначением другим персонажам, которые подали такой же запрос одновременно. Я ожидал, что каждый запрос будет выполнен отдельно, в последовательности. Как предотвратить пересечение запросов?

bot.message(contains:"$Wset") do |event|
    inputStr = event.content; # this should contain "$Wset#" where # is a single digit
    check_user_or_nick(event);  pIndex = nil;  #fetch the value of @user & set pIndex
    (0..(@player.length-1)).each do |y|  #find the @player pIndex within the array using 5 char of @user
        if (@player[y][0].index(@user.slice(0,5)) == 0) then pIndex = y;  end; #finds player Index Value (integer or nil)
    end;
    weaponInt = Integer(inputStr.slice(5,1)) rescue false; #will detect integer or non integer input
    if (pIndex != nil) && (weaponInt != false)  then; 
       if weaponInt < 6 then;
           @player[pIndex][1]=weaponInt;
           say = @player[pIndex][0].to_s + " weapon damage has be set to " + @weapon[(@player[pIndex][1])].to_s;
          else;
              say = "Sorry, $Wset requires this format: $Wset?  where ? is a single number ( 0 to 5 )";         
          end;
    else
       say = "Sorry, $Wset requires this format: $Wset?  where ? is a single number ( 0 to 5 )"; 
    end;
    event.respond say;
end;

1 Ответ

1 голос
/ 13 апреля 2020

Чтобы избежать таких условий гонки в многопоточном коде, главное, чтобы вы искали побочные эффекты .

Думайте о блоке bot.message(contains:"$Wset") do |event| как о мини программа или нить . Все здесь должно быть самодостаточным - для него не должно быть никакого способа воздействовать на другие потоки.

Изначально просматривая ваш код, я ищу любые 1014 * общие переменные . Они создают состояние гонки, если они читаются / записываются несколькими потоками одновременно.

В этом случае есть два очевидных нарушителя - @player и @user. Они должны быть реорганизованы в локальные переменные , а не переменные экземпляра . Определите их в блоке, чтобы они не влияли на другие области видимости, например:

# Note, for this to work, you will have to change
# the method definition to return [player, user]

player, user = check_user_or_nick(event)

Иногда создание побочных эффектов от потоков неизбежно (например, вы хотите создать счетчик для того, сколько раз поток был запущен). Чтобы предотвратить условия гонки в этих сценариях ios, Mutex обычно является решением, но также иногда распределенная блокировка , если код запускается на нескольких машинах . Однако, из кода, который вы показали, не похоже, что вам нужно что-то из этого здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...