Показаны сообщения с ярлыком Операционные системы. Показать все сообщения
Показаны сообщения с ярлыком Операционные системы. Показать все сообщения

суббота, 29 марта 2014 г.

Automatical prompting admin privileges launching an application on Mac os

If your application requires admin privileges and you don't want the user run it from command line with sudo then you can use Apple script to achieve it
First create an apple dropplet with the code below
on run
on run
 set appAlias to POSIX path of (path to resource "CamelAudioInstaller.app")
 set cmnd to appAlias & "Contents/MacOS/CamelAudioInstaller"
 
 #display dialog "You're going to launch the app without parameters" & cmnd buttons {"Ok"}
 do shell script cmnd with administrator privileges
end run
on open this_item
 set csPath to POSIX path of this_item
 set appAlias to POSIX path of (path to resource "CamelAudioInstaller.app")
 set cmnd to appAlias & "Contents/MacOS/CamelAudioInstaller " & csPath
 
 #display dialog "You're going to launch " & cmnd buttons {"Ok"}
 do shell script cmnd with administrator privileges
end open

Now after you double click the droplet you'll get the next


четверг, 17 октября 2013 г.

Getting current user's desktop path on Mac OS

The simplest solution is
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES );
NSString* theDesktopPath = [paths objectAtIndex:0];

But in the case of running the application in sudo mode it gives us the root's desktop path. To fix it use
 NSString* home = [[[NSProcessInfo processInfo] environment] objectForKey:@"HOME"];
 NSString *pathToDesktop = [NSString stringWithFormat:@"%@/Desktop", home];

пятница, 14 января 2011 г.

Многопоточное программирование. 3. Проблема производителя и потребителя

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

Рассмотрим упрощенный случай с двумя процессами. Первый процесс - Производитель (Producer), второй - Потребитель (Consumer).
Процессы используют общий буфер: Производитель помещает информацию в буфер, в то время как Потребитель извлекает ее, независимо от Производителя. Для Производителя всегда должно присутствовать незанятое место (слот) для записи информации, тогда как для Потребителя информация для извлечения должна присутствовать всегда, т.е. как минимум один непустой слот.
Производитель надеется на Потребителя, что тот предоставит свободное место для вставки очередной порции информации, а Потребитель надеется на Производителя, что тот обеспечит информацию для извлечения.
В таком случае Производитель и Потребитель каким-то образом должны взаимодействовать между собой, чтобы знать, что очередная вставка/извлечение будет безопасной для работающего в данный момент одного из процессов.

На первый взгляд решение, представленное ниже, абсолютно верное:

#define MAX_SIZE 100
int count = 0;
Producer()
{
  while (TRUE)
  {
    item = ProduceItem();
    if (count == MAX_SIZE) // (1) если буфер полон
    sleep(); // (2)
    InsertItem(item);
    ++count;
    if (count == 1)// был ли буфер пуст
      wakeup(Consumer);
  }
}

Consumer()
{
  while(TRUE)
  {
    if (count == 0) // (3) если буфер пуст
      sleep(); // (4)
    item = RemoveItem();
    --count;
    if (count == MAX SIZE - 1) // был ли буфер полон
      wakeup(Producer);
    ConsumeItem(item);
  }
}
count - количество слотов информации (или товаров, кому как) в буфере.
MAX_SIZE - максимальный размер буфера
Производитель сначала проверяет, не полон ли буфер, и если буфер полон, то Производитель засыпает, если не полон, то помещает информацию, увеличивает счетчик занятых слотов, и проверяет, не был ли буфер пусто до этого, если был пуст - значит Потребитель спит, и его надо разбудить.
Потребитель же наоборот, засыпает, когда буфер оказывается пустым. Если же после извлечения очередного элемента, Потребитель узнает, что до этого буфер был полным, значит Производитель спит и его надо разбудить.
Но в жизни все не так :-)

Представим, что буфер полон и работает Производитель. Осуществляется проверка на полноту буфера, и внезапно после выполнения строки (1), т.е. когда стало уже известно что надо заснуть, произошло переключение процесса. Теперь работает Потребитель. Он исправно извлекает информацию. Очистив первый слот, Потребитель понимает что буфер был полон, и нужно разбудет спящего, как ему кажется, производителя. Потребитель посылает сигнал пробуждения, и очищает буфер до конца, после чего засыпает. После этого происходит переключение на процесс Производителя, который не спал, а только собирался, и теперь он готов осуществить свою мечту - немного поспать. И засыпает. Все спят. Взаимоблокировка или deadlock.
А проблема, как уже многие догадались, состоит в утраченном вызове активизации процесса. Т.е. Производитель не спал, а его будили. К аналогичному результату привело бы рассмотрение ситуации, если бы буфер оказался пустым, и Потребитель решил бы уснуть, но "не успел".

Итак. Попробуем устранить проблему утраченного сигнала. Для этого будем использовать семафоры.
Cемафор - переменная, как правило целочисленная, используется для синхронизации доступа множества параллельно работающих процессов/потоков к общему ресурсу. Между семафором и обыкновенной численной переменной есть различия:
  • Будучи созданным, семафору можно присвоить любое значение (для counting semaphore), но операции, которые могут работать с семафором, ограничиваются лишь инкрементом и декрементом
  • Когда процесс/поток уменьшает значение семафора, и результат становится отрицательным, то он блокирует сам себя, и не может продолжать выполнение, пока другой процесс/поток не увеличит значение семафора
  • Если процесс/поток инкрементирует значение семафора, и есть ожидающие процессы, то один из них разблокируется
В нашем решении мы будем использовать 2 вида семафоров:
  • Counting semaphore (подсчитывающий)
  • Binary semaphore (двоичный, или мьютекс)

Вообще говоря, мьютекc и двоичный семафор это не одно и то же. Правильнее будет рассуждать, что двоичный семафор может быть использован как мьютекс, но не наоборот.
Двоичный семафор будет использоваться для управления доступом к буферу (чтобы в данный момент только один из потоков, а их может быть очень много, имел доступ к критической секции)
Подсчитывающие семафоры буду использоваться для подсчета свободных и занятых слотов буфера
#define MAX_SLOTS 100
typedef int semaphore;
semaphore mutex = 1;
semaphore empty = N; // подсчет пустых слотов в буфере
semaphore full = 0; // подсчет заполненных слотов буфере
Producer()
{
  int item;
  while (TRUE)
  {
    item = ProduceItem();
    down(empty); // (1)
    down(mutex); // (2)
    EnterItem(item);
    up(mutex); // (3)
    up(full); // (4)
  }
}
Consumer()
{
  int item;
  while (TRUE)
  {
    down(full); // (5)
    down(mutex); // (6)
    item = RemoveItem();
    up(mutex); // (7)
    up(empty); // (8)
    ConsumeItem(item);
  }
}
Итак, mutex отвечает за доступ одного процесса/потока в данный момент времени. Разберемся с empty и full. Пусть какое-то время программа работает, затем буфер заполняется полностью. Пусть в это время работает Производитель. Если буфер заполнен полностью, то empty = 0, это значит, что команда down(empty) приведет к блокировке Производителя (вспоминаем пункт 2 о семафорах). Далее работает Потребитель, разгружает слоты, регулирует семафоры количества пустых и полных слотов (количество пустых растет), и после первого очищения слота, Производитель может быть разблокирован, т.к. значение семафора увеличилось. Допустим произошло переключени на Производителя. Он продолжает выполнение со строки (2), заходит в критическую секцию, заполняет слот, выходит и увеличивает количество заполненных ячеек, тем самым позволяя Потребителю (если тот заблокирован) разблокироваться. В том и разница, что в данном случае Производитель не производит насильную разблокировку Потребителю, не задумываясь, надо ли это ему, а лишь создает условия, необходимые для разблокировки в случае, если таковая потребуется. Читателю предлагается проверить оставшиеся три граничные ситуации:
  • Буфер полон, работает Потребитель
  • Буфер пуст, работает Производитель
  • Буфер пуст, работает Потребитель
Уфффф!

четверг, 21 октября 2010 г.

Многопоточное программирование. 2. Алгоритм Петерсона... чуть более подробно. ч.2. Случай N процессов

В прошлый раз был рассмотрен алгоритм Петерсона для взаимного исключения двух процессов. На этот раз рассмотрим алгоритм Петерсона, обощенный на N параллельно выполняющихся процессов.
Код алгоритма:
#define FALSE  0
#define N     10

int turn[N];
int stage[N + 1];

void enterRegion(int process)
{ 
  for (int i = 1; i <= N - 1; i++) // перебор стадий
  {
    stage[process] = i;
    turn[i] = process;
    for (int j = 1; j <= N; j++) // "опрос" остальных процессов
    {
      if (j == process)
        continue;
      while (stage[j] >= i  && turn[i] == process);
    }
  }
}

void leaveRegion(int process)
{
  stage[process] = FALSE;
}
Для простоты и улучшения читабельности кода не будем рассматривать процесс с индексом 0, так же не будем рассматривать стадию с индексом 0, точнее стадия с индексом 0 будет своеобразным "стартом".
А теперь немного теории.
Алгоритм Петерсона для N процессов по сути тот же самый, что и для случая двух процессов, однако перед входом в критическую процесс должен преодолеть (n-1) стадий, т.н. "состязания". Количество стадий равно (n-1), потому что на каждой стадии будет оставаться хотя бы один процесс, а остальные будут переходить на следующую стадию, т.е. не более (n-j) процессов могут покинуть стадию под номером j. В конце концов у нас останется только два процесса, один из которых пройдет в критическую секцию. Два процесса будут как раз на (n-1)-й стадии. Преодоление каждой стадии напоминает версию для двух процессов, где один из процессов временно устраняется.
stage[process] - номер стадии, в которой находится процесс с идентификатором process
turn[i] = process - идентификатор процесса process, зашедшего последним в стадию под номером i

Рассмотрим поведение процессов на рисунке.

Пусть поочередно все 4 процесса попали на первую стадию. Пусть последним оказался процесс 1.
Происходит "опрос" остальных процессов на наличие их на той же самой стадии, где находится работающий процесс, либо на стадиях с бОльшим номером. Пусть вследствие прерываний до цикла, где происходит опрос, добрался процесс 2. В этом случае условие
while (stage[j] >= i  && turn[i] == process)
не выполнится.
Несмотря на то, что на данной стадии кроме процесса 2 имеются еще процессы, процесс 2 НЕ является последним перешедшим на данную стадию (мы условились, что последним будет процесс 1). Стало быть процесс 2 проходит на следующую стадию. И если так случится, что прерываний не будет, и его никто не "догонит", то процесс 2 благополучно войдет в критическую секцию, затем выйдет из нее, присвоит переменной interested[process] значение FALSE, что будет означать что данный процесс находится на стадии 0, т.е. на "старте", ну или на самой "низшей" стадии.
Если же переключению процессов случаются примерно через равные промежутки времени, то всегда для последнего процесса, зашедшего на данную стадию, условие
while (stage[j] >= i  && turn[i] == process)
не будет выполняться по той простой причине, что он последний: (turn[i] == process).
Таким образом на последующую стадию переходит на один процесс меньше, и так пока не останется двух процессов, после чего один из двух войдет в критическую секцию. Второй из двух войдет в критическую секцию после выхода первого, потому что (stage[j] >= i) будет равно FALSE. А если второго процесса кто либо "догонит", тем не менее (turn[i] == process) будет равно FALSE, и процесс все равно войдет в критическую секцию.

суббота, 2 октября 2010 г.

Многопоточное программирование. 1. Алгоритм Петерсона... чуть более подробно


Разберем сегодня алгоритм Петерсона. Посвящается всем начинающим, продолжающим,
прогулявшим пары по операционным системам и тем, до кого не дошло сразу. Алгоритм
Петерсона позволяет добиться взаимного исключения двух процессов. Рассмотрим 3 варианта поведения двух процессов при возникновении прерываний в трех различных точках. Также в каждом из рассмотренных случаев будем допускать прерывание при первом входе в критическую секциию одного из процессов
#define FALSE 0
#define TRUE 1
#define N 2 // количество процессов

int turn; // чья очередь
int interested[N];   // изначально значения равны 0

void enter_region(int process) // номер процесса - 0 или 1
{
  int other;
  other = 1 - process;    // точка 1
  interested[process] = TRUE;  // точка 2 (заинтересованный процесс)
  turn = process;         // точка 3
  while(turn == process && interested[other] == TRUE); // активное ожидание
}

void leave_region(int process) // номер процесса - 0 или 1
{
  interested[process] = 0; // признак выхода из критической секции
}
Итак, turn и interested[] являются глобальными переменными, прочие
переменные - локальные.
Случай 1: переключение процессов возникло в точке 1
Процесс 0 Процесс 1
other = 1
Прерывание процесса 0, переключение на процесс 1

other = 0, interested[1] = TRUE, turn = 1
Проверка условий turn == 1 (true) и interested[0] == TRUE (false)
Вход в критическую секцию
Прерывание процесса 1, переключение на процесс 0
interested[0] = TRUE, turn = 0
Проверка условий turn == 0 (true) и interested[1] == TRUE (true)
Вход в бесконечный цикл, переключение на процесс 1
Процесс 1 выходит из критической секции и устанавливает interested[1] = FALSE
Прерывание процесса 1, переключение на процесс 0
Проверка условий turn == 0 (true) и interested[1] == TRUE (false)
Вход в критическую секцию


Случай 2: переключение процессов возникло в точке 2
Процесс 0 Процесс 1
other = 1, interested[0] = TRUE
Прерывание процесса 0, переключение на процесс 1
other = 0, interested[1] = 1, turn = 1
Проверка условий turn == 1 (true) и interested[0] == TRUE (true)
Вход в бесконечный цикл, переключение на процесс 0
turn = 0
Проверка условий turn == 0 (true) и interested[1] == 1 (true)
Вход в бесконечный цикл, преключение на процесс 1

Проверка условий turn == 1 (false) и interested[0] == 1 (true)
Вход в критическую секцию
Прерывание процесса 1, переключение на процесс 0
Проверка условий turn == 0 (true) и interested[1] == 1 (true)
Вход в бесконечный цикл, преключение на процесс 1

Процесс 1 выходит из критической секции и устанавливает interested[1] = FALSE
Прерывание процесса 1, переключение на процесс 0
Проверка условий turn == 0 (true) и interested[1] == 1 (false)
Вход в критическую секцию

Случай 3: переключение процессов возникло в точке 3
Процесс 0 Процесс 1

other = 1, interested[0] = TRUE, turn = 0
Прерывание процесса 0, переключение на процесс
other = 0, interested[1] = TRUE, turn = 1
Проверка условий turn == 1 (true) и interested[0] == TRUE (true)
Вход в бесконечный цикл, преключение на процесс 0
Проверка условий turn == 0 (false) и interested[1] == TRUE (true)
Вход в критическую секцию
Прерывание процесса 0, переключение на процесс
Проверка условий turn == 1 (true) and interested[0] == TRUE (true)
Вход в бесконечный цикл, преключение на процесс 0
Процесс 0 выходит из критической секции и устанавливает interested[0] = FALSE
Прерывание процесса 0, переключение на процесс
Проверка условий turn == 1 (true) и interested[0] == TRUE (false)
Вход в критическую секцию


Продолжение следует...