LINUX.ORG.RU

История изменений

Исправление KivApple, (текущая версия) :

На самом деле можно сделать отдельные mutex на чтение и запись в кольцевой буфер, а указатели на элементы сделать volatile. При правильной реализаций будет потокобезопасно.

Например:

1. Заблокировать mutex чтения
2. Сравнить указатель на начало и конец данных, если равны, то ждать (либо busyloop, либо condition variables), либо вернуть ошибку (разлочив mutex)
3. Считать элемент, затем инкрементировать позицию начала (если достигнет конца, обнулить)
4. Перейти к шагу 2, если надо считать больше байт, иначе разлочить mutex
1. Заточить mutex записи
2. Убедиться, что в буфере есть место, сравнив правильно указатели на начало и конец, если места нет, то вернуть ошибку, либо ждать, пока условие изменится
3. Записать элемент, затем инкрементировать позицию записи (обнулить, если дойдет до конца)
4. Отпустить mutex

То есть фактически синхронизирован только доступ к одному указателю буфера, а к другому происходит без синхронизации (именно поэтому нужен volatile, а лучше даже спецфункции атомарного записи/чтения для барьеров памяти). Но это не страшно, ведь если ты внимательно просимулируешь поведение этого кода, то увидишь, что в случае конфликта (в середине одна функция была прервана и запущена другая) максимум, что тебе грозит - кто-то уйдет на дополнительный цикл ожидания (это реализуется за счёт того, что ты сначала кладешь данные в буфер и только потом обновляешь указатель, а при чтении сначала забираешь, поскольку каждая сторона умеет изменять только свой указатель, получается безопасно).

Если у тебя один читатель и один писатель, то оверхеда от блокировок не будет (ведь блокировка mutex всегда будет происходить мгновенно, потому что его никто не держит).

Исправление KivApple, :

На самом деле можно сделать отдельные mutex на чтение и запись в кольцевой буфер, а указатели на элементы сделать volatile. При правильной реализаций будет потокобезопасно.

Например:

1. Заблокировать mutex чтения
2. Сравнить указатель на начало и конец данных, если равны, то ждать (либо busyloop, либо condition variables), либо вернуть ошибку (разлочив mutex)
3. Считать элемент, затем инкрементировать позицию начала (если достигнет конца, обнулить)
4. Перейти к шагу 2, если надо считать больше байт, иначе разлочить mutex
1. Заточить mutex записи
2. Убедиться, что в буфере есть место, сравнив правильно указатели на начало и конец, если места нет, то вернуть ошибку, либо ждать, пока условие изменится
3. Записать элемент, затем инкрементировать позицию записи (обнулить, если дойдет до конца)
4. Отпустить mutex

То есть фактически синхронизирован только доступ к одному указателю буфера, а к другому происходит без синхронизации (именно поэтому нужен volatile, а лучше даже спецфункции атомарного записи/чтения для барьеров памяти). Но это не страшно, ведь если ты внимательно просимулируешь поведение этого кода, то увидишь, что в случае конфликта (в середине одна функция была прервана и запущена другая) максимум, что тебе грозит - кто-то уйдет на дополнительный цикл ожидания (это реализуется за счёт того, что ты сначала кладешь данные в буфер и только потом обновляешь указатель, а при чтении сначала забираешь, поскольку каждая сторона умеет отравлять только свой указатель, получается безопасно).

Если у тебя один читатель и один писатель, то оверхеда от блокировок не будет (ведь блокировка mutex всегда будет происходить мгновенно, потому что его никто не держит).

Исправление KivApple, :

На самом деле можно сделать отдельные mutex на чтение и запись в кольцевой буфер, а указатели на элементы сделать volatile. При правильной реализаций будет потокобезопасно.

Например:

1. Заблокировать mutex чтения
2. Сравнить указатель на начало и конец данных, если равны, то ждать (либо busyloop, либо condition variables), либо вернуть ошибку (разлочив mutex)
3. Считать элемент, затем инкрементировать позицию начала (если достигнет конца, обнулить)
4. Перейти к шагу 2, если надо считать больше байт, иначе разлочить mutex
1. Заточить mutex записи
2. Убедиться, что в буфере есть место, сравнив правильно указатели на начало и конец, если места нет, то вернуть ошибку, либо ждать, пока условие изменится
3. Записать элемент, затем инкрементировать позицию записи (обнулить, если дойдет до конца)
4. Отпустить mutex

То есть фактически синхронизирован только доступ к одному указателю буфера, а к другому происходит без синхронизации (именно поэтому нужен volatile, а лучше даже спецфункции атомарного записи/чтения для барьеров памяти. Но это не страшно, ведь если ты внимательно просимулируешь поведение этого кода, то увидишь, что в случае конфликта (в середине одна функция была прервана и запущена другая) максимум, что тебе грозит - кто-то уйдет на дополнительный цикл ожидания (это реализуется за счёт того, что ты сначала кладешь данные в буфер и только потом обновляешь указатель, а при чтении сначала забираешь, поскольку каждая сторона умеет отравлять только свой указатель, получается безопасно).

Если у тебя один читатель и один писатель, то оверхеда от блокировок не будет (ведь блокировка mutex всегда будет происходить мгновенно, потому что его никто не держит).

Исправление KivApple, :

На самом деле можно сделать отдельные mutex на чтение и запись в кольцевой буфер, а указатели на элементы сделать volatile. При правильной реализаций будет потокобезопасно.

Например:

1. Заблокировать mutex чтения
2. Сравнить указатель на начало и конец данных, если равны, то ждать (либо busyloop, либо condition variables), либо вернуть ошибку (разлочив mutex)
3. Считать элемент, затем инкрементировать позицию начала (если достигнет конца, обнулить)
4. Перейти к шагу 2, если надо считать больше байт, иначе разлочить mutex
1. Заточить mutex записи
2. Убедиться, что в буфере есть место, сравнив правильно указатели на начало и конец, если места нет, то вернуть ошибку, либо ждать, пока условие изменится
3. Записать элемент, затем инкрементировать позицию записи (обнулить, если дойдет до конца)
4. Отпустить mutex

То есть фактически синхронизирован только доступ к одному указателю буфера, а к другому происходит без синхронизации (именно поэтому нужен volatile, а лучше даже спецфункции атомарного записи/чтения для барьеров памяти. Но это не страшно, ведь если ты внимательно просимулируешь поведение этого кода, то увидишь, что в случае конфликта (в середине одна функция была прервана и запущена другая) максимум, что тебе грозит - кто-то уйдет на дополнительный цикл ожидания (это реализуется за счёт того, что ты сначала кладешь данные в буфер и только потом обновляешь указатель, а при чтении сначала забираешь, поскольку каждая сторона умеет отравлять только свой указатель, получается безопасно).

Исправление KivApple, :

На самом деле можно сделать отдельные mutex на чтение и запись в кольцевой буфер, а указатели на элементы сделать volatile. При правильной реализаций будет потокобезопасно.

Например:

1. Заблокировать mutex чтения
2. Сравнить указатель на начало и конец данных, если равны, то ждать (либо busyloop, либо condition variables), либо вернуть ошибку (разлочив mutex)
3. Считать элемент, затем инкрементировать позицию начала (если достигнет конца, обнулить)
4. Перейти к шагу 2, если надо считать больше байт, иначе разлочить mutex
1. Заточить mutex записи
2. Убедиться, что в буфере есть место, сравнив правильно указатели на начало и конец, если места нет, то вернуть ошибку, либо ждать, пока условие изменится
3. Записать элемент, затем инкрементировать позицию записи (обнулить, если дойдет до конца)
4. Отпустить mutex

То есть фактически синхронизирован только доступ к одному указателю буфера, а к другому происходит без синхронизации (именно поэтому нужен volatile, а лучше даже спецфункции атомарного записи/чтения для барьеров памяти. Но это не страшно, ведь если ты внимательно просимулируешь поведение этого кода, то увидишь, что в случае конфликта (в середине одна функция была прервана и запущена другая) максимум, что тебе грозит - кто-то уйдет на дополнительный цикл ожидания.

Исходная версия KivApple, :

На самом деле можно сделать отдельные mutex на чтение и запись в кольцевой буфер, а указатели на элементы сделать volatile. При правильной реализаций будет потокобезопасно.

Например:

1. Заблокировать mutex чтения
2. Сравнить указатель на начало и конец данных, если равны, то ждать (либо busyloop, либо condition variables), либо вернуть ошибку (разлочив mutex)
3. Считать элемент, затем инкрементировать позицию начала (если достигнет конца, обнулить)
4. Перейти к шагу 2, если надо считать больше байт, иначе разлочить mutex
1. Заточить mutex записи
2. Убедиться, что в буфере есть место, сравнив правильно указатели на начало и конец, если места нет, то вернуть ошибку, либо ждать, пока условие изменится
3. Записать элемент, затем инкрементировать позицию записи (обнулить, если дойдет до конца)
4. Отпустить mutex

То есть фактически синхронизирован только доступ к одному указателю буфера, а к другому происходит без синхронизации (именно поэтому нужен volatile, а лучше даже спецфункции атомарного записи/чтения. Но это не страшно, ведь если ты внимательно просимулируешь поведение этого кода, то увидишь, что в случае конфликта (в середине одна функция была прервана и запущена другая) максимум, что тебе грозит - кто-то уйдет на дополнительный цикл ожидания.