Изменения всех объектов связанных с интерфейсными правильней всего делать в потоке интерфейсного объекта (хотя исключения наверное есть)
Делал я также, через lock, и было все нормально, пока не написал тестовый генератор таблиц, и столкнулся с
иногда выскакивающим эксэпшеном из глубин грида, если в DataTable менялось количество строк
А когда сделал (у меня грид был один, а DataTable'ов много):
// если в другом от грида потоке изменяется таблица которая сейчас отображется, то изменяем ее в потоке грида
if (lastGrid.InvokeRequired && lastGrid.DataSource == dTable) lastGrid.Invoke(delegate () {UpdtForms(...})
// а иначе - просто меняем.
else UpdtForms(...
все стало работать стабильно.
Понятно, что раз в потоке грида приходится менять то там нужно минимум работы делать, иначе теряется смысл второго потока.