• Как продвинуть сайт на первые места?
    Вы создали или только планируете создать свой сайт, но не знаете, как продвигать? Продвижение сайта – это не просто процесс, а целый комплекс мероприятий, направленных на увеличение его посещаемости и повышение его позиций в поисковых системах.
    Ускорение продвижения
    Если вам трудно попасть на первые места в поиске самостоятельно, попробуйте технологию Буст, она ускоряет продвижение в десятки раз, а первые результаты появляются уже в течение первых 7 дней. Если ни один запрос у вас не продвинется в Топ10 за месяц, то в SeoHammer за бустер вернут деньги.
  • Сервис онлайн-записи на собственном Telegram-боте
    Тот, кто работает в сфере услуг, знает — без ведения записи клиентов никуда. Мало того, что нужно видеть свое расписание, но и напоминать клиентам о визитах тоже. Нашли самый бюджетный и оптимальный вариант: сервис VisitTime.
    Для новых пользователей первый месяц бесплатно.
    Чат-бот для мастеров и специалистов, который упрощает ведение записей:
    Сам записывает клиентов и напоминает им о визите;
    Персонализирует скидки, чаевые, кэшбэк и предоплаты;
    Увеличивает доходимость и помогает больше зарабатывать;


Иллюстрированный самоучитель по Visual Studio .NET

Стратегии решения проблемы

Для того чтобы исключить подобный сценарий, автор многопотокового приложения должен решать проблему синхронизации при попытке одновременного доступа к разделяемым ресурсам. Если говорить о файлах с совместным доступом, то сходная ситуация может возникнуть и при столкновении различных процессов, а не только потоков одного процесса. Разработчика в этом случае уже не устроит стандартный способ открытия файла. Например:

//======= Создаем объект класса CFile
CFile file;
// ====== Строка с именем файла
CString fn("MyFile.dat");
//===== Попытка открыть файл для чтения
if (! file.Open(fn,CFile::modeRead))
{
MessageBox ("He могу открыть файл "+fn, "Ошибка");
return;
}

Он должен писать код с учетом того, что файл может быть заблокирован какое-то время другим процессом. Если следовать уже рассмотренной тактике ожидания ресурса в течение какого-то времени, то надо создать код вида:

bool CMyWnd::TryOpen()
<
//====== Попытка открыть файл и внести изменения
CFile file;
CString fn("MyFile.dat"), Buffer;
//===== Флаг первой попытки
static bool bFirst = true;
if (file.Open (fn, CFile:: modeReadWrite I CFile::shareExclusive))
{
// Никакая другая программа не сможет открыть
// этот файл, пока мы с ним работаем
int nBytes = flie.Read(Buffer,MAX_BYTES);
//==== Работаем с данными из строки Buffer
//==== Изменяем их нужным нам образом
//==== Пришло время вновь сохранить данные
file.Write(Buffer, nBytes);
file. Close ();
//==== Начиная с этого момента, файл доступен
//==== для других процессов
//==== Если файл был открыт не с первой попытки,
//==== то выключаем таймер ожидания
if (IbFirst)
KillTimer(WAIT_ID);
//===== Возвращаем флаг успеха
return bFirst = true;
}
//====== Если не удалось открыть файл
else
if (bFirst) // и эта неудача – первая,
//===== то запускаем таймер ожидания
SetTiraer(WAIT_ID, 1000, 0);
//===== Возвращаем флаг неудачи
return bFirst = false;
}

В другой функции, реагирующей на сообщения таймера, называемой, как вы знаете, функцией-обработчиком (Message Handler), надо предусмотреть ветвь для реализации выбранной тактики ожидания:

//====== Обработка сообщений таймера
void CMyWnd::OnTimer(UINT nID)
{
//====== Счетчик попыток
static int iTrial = 0;
//====== Переход по идентификатору таймера
switch (nID)
{
//== Здесь могут быть ветви обработки других таймеров
case WAIT_ID:
//====== Если не удалось открыть
if (ITryOpenO)
{
//===== и запас терпения не иссяк,
if (++iTrial < 10)
return; // то продолжаем ждать
//=== Если иссяк, то сообщаем о полной неудаче
else
{
MessageBox ("Файл занят более 10 секунд", "Ошибка");
 //====== Отказываемся ждать
KillTimer(WAIT_ID);
//====== Обновляем запас терпения
iTrial = 0;
}
}
}
}

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

Одним из более эффективных решений может быть такое: первый поток читает запись, вычисляет прибавку и только после этого блокирует, изменяет и освобождает запись. Такое решение может снизить время блокирования до нескольких миллисекунд. Однако защита данных теперь не сработает в случае, если другой поток поступает также. Второй поток может прочитать запись после того, как ее прочел первый, но до того, как первый начал изменять запись. Как поступить в этом случае? Можно, например, ввести механизм слежения за доступом к записи, и если к записи было обращение в интервале между чтением и модификацией, то отказаться от модификации и повторить всю процедуру вновь.

Примечание
Каждое решение создает новые проблемы, а поиск оптимального баланса ложится на плечи программиста, делая его труд еще более интересным. Кстати, последнее решение может вызвать ситуацию, сходную с той, когда два человека уступают друг другу дорогу. Отметьте, что решение вопроса кроется в балансе между производительностью (performance) и целостностью данных (data integrity)
.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.