Появляется лишняя строка в таблице

Страницы: 1
RSS
Появляется лишняя строка в таблице
 
Демонстрационный скрипт:
Код
function OnStop()
  run = nil
  SetCell(id, 1, 1, string.format('Size: %u', GetTableSize(id)))  -- Почему-то попадаем в строку 2
end

local alltrade
function OnAllTrade()
  if not run then return end
  alltrade = true
  for i = 1, 30 do
    DeleteRow(id, 1)
    InsertRow(id, 30)
  end
end

function main()
  id = AllocTable()
  AddColumn(id, 1, 'Size', true, QTABLE_INT_TYPE, 15)
  CreateWindow(id)
  SetWindowPos(id, 0, 0, 100, 520)
  for i = 1, 30 do
    InsertRow(id, -1)
  end

  run = true
  while run do
    if alltrade then
      alltrade = nil
      SetCell(id, 30, 1, string.format('%u', GetTableSize(id)))
    else sleep(1) end
  end
end

Через некоторое время работы появляется 31 строка. Первая строка становится недоступна для редактирования.

Видео
 
Старатель,
Проблема изучается. Постараемся в ближайшее время дать ответ.
 
Старатель, добрый день,

Проблема вызвана тем, что работа с таблицей в скрипте осуществляется из разных потоков без синхронизации.

Сценарий проблемы следующий:
- OnAllTrade вызывается из основного потока программы. В ней скрипт выполняет очистку таблицы;
- одновременно в функции main(), работающей в потоке скрипта, вызывается функция SetCell, которая обновляет строку;
- возможна ситуация, при которой строка уже удалена, но новая не вставлена. Если SetCell сработает между этими вызовами, то, так как строка уже удалена и не найдена, она будет добавлена вновь.
 
Цитата
Evgeniy Karnaukhov написал:
так как строка уже удалена и не найдена, она будет добавлена вновь.
Зачем?

Цитата
Evgeniy Karnaukhov написал:
Проблема вызвана тем, что работа с таблицей в скрипте осуществляется из разных потоков без синхронизации.
Можете предложить рабочий пример?
Такой вариант тоже не работает:
Код
function OnAllTrade()
  if not run then return end
  alltrade = true
  for i = 1, rows do
    table.ssort({0, 0}, function()
      DeleteRow(id, 1)
      InsertRow(id, rows)
      return true
    end)
  end
end
 
Цитата
Старатель написал:
Такой вариант тоже не работает
А если в мейне тоже в критическую секцию завернуть?
 
Цитата
Anton написал:
в мейне тоже в критическую секцию завернуть
QUIK повесится
 
Цитата
Старатель написал:
QUIK повесится
Кажется понял, почему виснет. Мейн у нас в отдельном потоке, работа с таблицей так или иначе приводит к SendMessage окну (в основной поток то есть), и собственно все, основной поток стоит на критической секции в колбеке и обработать сообщение не может. Если так, надо либо из мейна в окно не лазить, либо из колбеков (всех). Сиречь либо редиректить события в мейн и лазить только оттуда, либо лазить только из колбеков. Ну либо хачить со всеми вытекающими.
 
В связи с этой проблемой возникла такая мысль, а что если нам попросить такую фичу: функция для вызова пользовательского колбека в основном потоке и соответствующий колбек. То есть например
Код
ANYTYPE SendCustomNotification(ANYTYPE v)
ANYTYPE OnCustomNotification(ANYTYPE v)
с простой реализацией: первая посылает сообщение главному окну со ссылкой на произвольный юзерский тип, главное окно по получении сообщения дергает колбек с полученным значением и возвращенное значение возвращает из сообщения. Если посылаем из мейна - мейн встает и ждет, пока в главном потоке выполнится колбек, причем это "даром", за счет свойств винды. Если посылаем из другого колбека - колбек выполняется синхронно, тоже за счет свойств винды. Это хоть какая-то синхронизация была бы, а то ж сейчас ее нет от слова совсем. Приглашаю накидать аргументов против, если кому интересно.
 
Цитата
Evgeniy Karnaukhov написал:
Если SetCell сработает между этими вызовами, то, так как строка уже удалена и не найдена, она будет добавлена вновь.
Зачем?

Цитата
Evgeniy Karnaukhov написал:
возможна ситуация, при которой строка уже удалена, но новая не вставлена.
Пример без InsertRow:
Код
rows = 20
function OnParam()
  if not run then return end
  rows = rows - 1
  DeleteRow(id, 1)
  if rows == 10 then run = nil end
end

function main()
  id = AllocTable()
  AddColumn(id, 1, 'row', true, QTABLE_INT_TYPE, 15)
  CreateWindow(id)
  SetWindowPos(id, 0, 0, 110, 350)
  for i = 1, rows do InsertRow(id, -1) end

  run = true
  while run do
      SetCell(id, 5, 1, tostring(rows))
      sleep(1)
  end
  for row = 0, GetTableSize(id) do
    SetCell(id, row, 1, tostring(row))
  end
end

Результат:


Обсуждаемая проблема может возникнуть в любом скрипте, в котором в одном потоке пишутся данные в таблицу, а в другом удаляется строка из начала/середины таблицы.
Предложение Антона создать пользовательский колбек выглядит разумным. Да и в других ситуациях такой колбек не помешал бы.
Страницы: 1
Читают тему (гостей: 1)
Наверх