Здравствуйте, Donz, Вы писали:
D>Если действительно "Основной поток пускал 4 рассчитывающих потока и ждал их окончания.", то не нужны никакие атомики. После окончания работы нить обязана скинуть все, что она закешировала (иначе смысла нет — результат работы уйдет вместе с кешом в GC). D>Думаю, что проблема в логике разбиения массива на логические куски. D>Можно код?
блин странная фигня.... 3 дня парился, а сейчас не воспроизводится...
я в общем то примерно так и рассуждал сначал, но потом стал сомневаться....
сделал простенький тест-кейс. Fork/Join брал у ее создателя Дуга Ли: тут
public class Processor implements Callable<Boolean>
{
private final int from;
private final int to;
private final double[] ii;
public Processor(int from, int to, double[] ii)
{
this.from = from;
this.to = to;
this.ii = ii;
}
@Override
public Boolean call()
{
for (int i = from; i < to; i++)
{
// просто хоть что-то посчитать, имитация реальных вычисленийfor (int j = from; j < to; j++)
ii[i] += j;
}
return (Boolean.TRUE);
}
}
----------------
import jsr166y.ForkJoinPool;
public class ArrayOfDoublesTest
{
private final double[] ii;
public ArrayOfDoublesTest(int arraySize)
{
ii = new double[arraySize];
}
public void process(int parallelism)
{
System.out.printf("Parallelism = %d%n", parallelism);
Arrays.fill(ii, 0);
List<Processor> tasks = new ArrayList<Processor>(parallelism);
int delta = ii.length / parallelism;
int lo = 0;
for (int i = 0; i < parallelism; i++)
{
int hi = lo + delta;
// гарантируем что для в последний кусок попадет все что осталосьif (i == (parallelism-1))
{
hi = ii.length;
}
tasks.add(new Processor(lo, hi, ii));
}
// вызываем все задачи
ForkJoinPool pool = new ForkJoinPool(parallelism);
pool.invokeAll(tasks);
for (int i = 0; i < ii.length; i++)
{
if (ii[i] == 0)
System.out.printf("Failed for ii[%d]!%n", i);
}
}
/**
* @param args
*/public static void main(String[] args)
{
ArrayOfDoublesTest test = new ArrayOfDoublesTest(50000);
test.process(1);
test.process(2);
test.process(3);
test.process(4);
}
}
Re[2]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Большой массив — это блок памяти. Тот факт, что он непрерывный — к делу не относится. Если бы он не был непрерывным, ничего бы не менялось в плане этой проблемы. PD>Тогда, получается, разные потоки могли бы писать в разные блоки памяти, и при этом возникали бы какие-то проблемы. Если бы они возникали, это подорвало бы вообще всю идею потоков — мало ли кто куда пишет.
В том то и проблема если массив это кусок, и кешируется он кусками — то получается проблема синхронизации и кешей.
Re[7]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Nicht, Вы писали:
N>Ну что значит после все равно не сильно понятно. Если стоит join() то да. Если же какая то другая магия, то не факт.
Автор как раз использовал join.
N>Про это сказано в спеке N>
N>The final action in a thread T1 synchronizes-with any action in another thread T2 that detects that T1 has terminated. T2 may accomplish this by calling T1.isAlive() or T1.join().
N>Тоесть если поток завершился и никто у него не спросил что он завершился, то и изменения могут и не увидеть.
Не совсем понял. Нить T1 завершилась, то есть метод run полностью выполнился, сам объект Runnable давно собран GC, как и созданный Thread, а изменения все еще могут быть не доступны другим нитям, пока они явно не спросят, а не умерла ли нить T1?
Не могу найти нужный пруфлинк, но это была бы очень странная ситуация.
Re[8]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Donz, Вы писали:
D>Здравствуйте, Nicht, Вы писали:
N>>Ну что значит после все равно не сильно понятно. Если стоит join() то да. Если же какая то другая магия, то не факт.
D>Автор как раз использовал join.
Ну тогда хорошо
N>>Про это сказано в спеке N>>
N>>The final action in a thread T1 synchronizes-with any action in another thread T2 that detects that T1 has terminated. T2 may accomplish this by calling T1.isAlive() or T1.join().
N>>Тоесть если поток завершился и никто у него не спросил что он завершился, то и изменения могут и не увидеть.
D>Не совсем понял. Нить T1 завершилась, то есть метод run полностью выполнился, сам объект Runnable давно собран GC, как и созданный Thread, а изменения все еще могут быть не доступны другим нитям, пока они явно не спросят, а не умерла ли нить T1? D>Не могу найти нужный пруфлинк, но это была бы очень странная ситуация.
Ну судя по спеке, да. Если нет синхронайзед ордера, тоесть никто не хочет воспользоваться результатами работы потока, то и результат никто может не увидеть.
Re[9]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Nicht, Вы писали:
D>>Не совсем понял. Нить T1 завершилась, то есть метод run полностью выполнился, сам объект Runnable давно собран GC, как и созданный Thread, а изменения все еще могут быть не доступны другим нитям, пока они явно не спросят, а не умерла ли нить T1? D>>Не могу найти нужный пруфлинк, но это была бы очень странная ситуация. N>Ну судя по спеке, да. Если нет синхронайзед ордера, тоесть никто не хочет воспользоваться результатами работы потока, то и результат никто может не увидеть.
Да, ситуация запуска нитей без синхронизации контекста сама по себе странная, но подобное поведение после смерти нити еще более страннее.
Re[3]: Запись в массив double-ов из нескольких потоков
Здравствуйте, zubr, Вы писали:
Z>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Большой массив — это блок памяти. Тот факт, что он непрерывный — к делу не относится. Если бы он не был непрерывным, ничего бы не менялось в плане этой проблемы. PD>>Тогда, получается, разные потоки могли бы писать в разные блоки памяти, и при этом возникали бы какие-то проблемы. Если бы они возникали, это подорвало бы вообще всю идею потоков — мало ли кто куда пишет.
Z>В том то и проблема если массив это кусок, и кешируется он кусками — то получается проблема синхронизации и кешей.
А если не один массив, а несколько ,и в каждый пишет свой поток ?
А если вообще разные структуры данных, и в каждую из них пишет свой поток ?
Так мы можем дойти до требования какого-то специального размещения данных для потоков, что будет совсем уж ни в какие ворота.
With best regards
Pavel Dvorkin
Re[5]: Запись в массив double-ов из нескольких потоков
Здравствуйте, abch-98-ru, Вы писали:
A9R>>>вроде уже обсудили. B>>Нет, не обсудили. A9R>Ещё актуально? Если есть вопрос — сформулируйте, пожалуйста.
Какие существуют предпосылки к тому запись в разные массивы была не потокобезопасной. Может ли массив (достаточно большой) целиком кешироваться в памяти\реестрах выделеных потоку.
Re[7]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, abch-98-ru, Вы писали:
A9R>>>>вроде уже обсудили. B>>>Нет, не обсудили. A9R>>Ещё актуально? Если есть вопрос — сформулируйте, пожалуйста. B>Какие существуют предпосылки к тому запись в разные массивы была не потокобезопасной. Может ли массив (достаточно большой) целиком кешироваться в памяти\реестрах выделеных потоку.
А чем, простите, разные массивы отличаются от одного массива ?
Сорри, перейду на С
union A {
struct A2
{ int a[10];
int b[10];
};
int c[20];
};
Это один или два массива ? Можно считать и так, и так.
И вообще, с каких это пор расположение объектов в виртуальной памяти на что-то влияет ?
With best regards
Pavel Dvorkin
Re[8]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Это один или два массива ? :-) Можно считать и так, и так. PD>И вообще, с каких это пор расположение объектов в виртуальной памяти на что-то влияет ?
Это здесь к чему? Вот есть ключевое слово volatile. Оно применяется к переменной-полю. Если мы спроецируем абстракцию, то элемент массива это переменная. Она работает так же как volatile поле, или иначе?
Re[9]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Blazkowicz, Вы писали:
B>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Это один или два массива ? Можно считать и так, и так. PD>>И вообще, с каких это пор расположение объектов в виртуальной памяти на что-то влияет ? B>Это здесь к чему? Вот есть ключевое слово volatile. Оно применяется к переменной-полю. Если мы спроецируем абстракцию, то элемент массива это переменная. Она работает так же как volatile поле, или иначе?
При чем тут volatile ? Его употребляют, когда надо проинформировать компилятор, что переменную надо брать всегда из памяти, а не из регистра, так как она может быть изменена в другом месте. Где тут переменные (или элементы массива), которые могут измениться в другом месте, если по условиям ТС каждый поток работает строго со своими элементами ?
А к тому это здесь, что заведи один массив или несколько массивов — это ничего не меняет в плане доступа к ним потоков, если потоки не обращаются к одним и тем же элементам.
With best regards
Pavel Dvorkin
Re[7]: Запись в массив double-ов из нескольких потоков
A9R>>>>вроде уже обсудили. B>>>Нет, не обсудили. A9R>>Ещё актуально? Если есть вопрос — сформулируйте, пожалуйста. B>Какие существуют предпосылки к тому запись в разные массивы была не потокобезопасной.
если программа только пишет в разные массивы — то race-ов нет, всё потокобезопасно.
если и читает, то есть нюансы:
если существуют два action-а не под happens-before над variable(term variable to refer to both fields and array elements)и один из них write, то это race и, стал быть, программа не потокобезопасна.
B>Может ли массив (достаточно большой) целиком кешироваться в памяти\реестрах выделеных потоку.
кэширование не обсуждается в jls3(только в jls2) так что если не писать java-код под конкретную jvm — версия — архитектура, то это(может или нет кэшироваться) неопределено и может быть изменено.
Re[8]: Запись в массив double-ов из нескольких потоков
Здравствуйте, abch-98-ru, Вы писали:
A9R>если программа только пишет в разные массивы — то race-ов нет, всё потокобезопасно.
В один массив. Разные индексы.
И если такие безопасно, то осталось разобраться, почему у автора это не так.
Re[9]: Запись в массив double-ов из нескольких потоков
A9R>>если программа только пишет в разные массивы — то race-ов нет, всё потокобезопасно. B>В один массив. Разные индексы.
в твоём вопросе было B>Какие существуют предпосылки к тому запись в разные массивы была не потокобезопасной.
но даже с изменённым условием, при наличии только записи всё будет потокобезопасно.
B>И если такие безопасно, то осталось разобраться, почему у автора это не так.
у автора есть, по крайней мере, чтение.
Re[10]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Blazkowicz, Вы писали:
B>>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>>Это один или два массива ? Можно считать и так, и так. PD>>>И вообще, с каких это пор расположение объектов в виртуальной памяти на что-то влияет ? B>>Это здесь к чему? Вот есть ключевое слово volatile. Оно применяется к переменной-полю. Если мы спроецируем абстракцию, то элемент массива это переменная. Она работает так же как volatile поле, или иначе?
PD>При чем тут volatile ? Его употребляют, когда надо проинформировать компилятор, что переменную надо брать всегда из памяти, а не из регистра, так как она может быть изменена в другом месте. Где тут переменные (или элементы массива), которые могут измениться в другом месте, если по условиям ТС каждый поток работает строго со своими элементами ?
PD>А к тому это здесь, что заведи один массив или несколько массивов — это ничего не меняет в плане доступа к ним потоков, если потоки не обращаются к одним и тем же элементам.
Это все устарело с выходом JSR 133 (Java Memory Model).
Re[10]: Запись в массив double-ов из нескольких потоков
Здравствуйте, abch-98-ru, Вы писали:
B>>В один массив. Разные индексы. A9R>в твоём вопросе было B>>Какие существуют предпосылки к тому запись в разные массивы была не потокобезопасной.
Опечатался. :shuffle:
Re[11]: Запись в массив double-ов из нескольких потоков
PD>>А к тому это здесь, что заведи один массив или несколько массивов — это ничего не меняет в плане доступа к ним потоков, если потоки не обращаются к одним и тем же элементам.
N>Это все устарело с выходом JSR 133 (Java Memory Model).
Речь идет о доступе к разным байтам (словам и т.д.) памяти. Потоки не имеют общих данных.
With best regards
Pavel Dvorkin
Re[12]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Nicht, Вы писали:
PD>>>А к тому это здесь, что заведи один массив или несколько массивов — это ничего не меняет в плане доступа к ним потоков, если потоки не обращаются к одним и тем же элементам.
N>>Это все устарело с выходом JSR 133 (Java Memory Model).
PD>Речь идет о доступе к разным байтам (словам и т.д.) памяти. Потоки не имеют общих данных.
Где идет речь?
Re[9]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Blazkowicz, Вы писали:
PD>>Это один или два массива ? Можно считать и так, и так. PD>>И вообще, с каких это пор расположение объектов в виртуальной памяти на что-то влияет ? B>Это здесь к чему? Вот есть ключевое слово volatile. Оно применяется к переменной-полю. Если мы спроецируем абстракцию, то элемент массива это переменная. Она работает так же как volatile поле, или иначе?
Очень не уверен, что это обобщение правильно. С точки зрения языка это совершенно разные контейнеры памяти. И на уровне байт-кода применяются разные инструкции для чтения и записи данных в поле и в ячейку массива.
ИМХО, сам массив не может кешироваться нитью. Кешироваться могут только поля (примитивные типы или ссылки на объекты).
Re[13]: Запись в массив double-ов из нескольких потоков
Здравствуйте, Nicht, Вы писали:
N>>>Это все устарело с выходом JSR 133 (Java Memory Model).
PD>>Речь идет о доступе к разным байтам (словам и т.д.) памяти. Потоки не имеют общих данных.
N>Где идет речь?