Sistemas Operativos
Sincronização de threads com objectos kernel no Windows
João Pedro Patriarca (jpatri@cc.isel.ipl.pt)
Centro de Cálculo
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Objectos Kernel
• Processes
• Threads
• Jobs
• File and console standard input/output/error streams
• Events
• Waitable timers
• Semaphores
• Mutexes
• Um objecto pode estar sinalizado ou não
• Uma thread pode-se colocar no estado Wait até que um objecto fique
sinalizado
• As regras de sinalização dos objectos dependem do tipo concreto de
objecto: ex, processos e threads sinalizados indicam a sua terminação;
uma vez atingido esse estado, não mais sairão
• Um objecto kernel é partilhável por vários processos
2
Objectos usados para
sincronização de threads
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Funções de espera (Wait) de sinalização de objectos
DWORD WaitForSingleObject(
HANDLE hObject,
DWORD dwMilliseconds);
dwMilliseconds = INFINITE = 0xFFFFFFFF (-1)
• Retorna WAIT_FAILED, WAIT_TIMEOUT, WAIT_OBJECT_0
• Esperar por um objecto sinalizado promove o retorno imediato
DWORD WaitForMultipleObjects(
DWORD dwCount,
CONST HANDLE * phObjects,
BOOL bWaitAll,
DWORD dwMilliseconds);
• bWaitAll: true = espera por todos
• No caso de sucesso, retorna WAIT_OBJECT_0 + N,
– com N igual a 0 se bWaitAll a true
– com N igual ao valor do índice do objecto sinalizado se bWaitAll a false;
especial atenção ao objecto sinalizado se pretender-se chamar a função de
espera novamente
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Consequências da espera por sinalização de objectos
• A espera com sucesso por sinalização em alguns objectos promove
a alteração de estado nos próprios objectos
• Um retorno sem sucesso nunca altera o estado do objecto
• A função WaitForMultipleObjects garante atomicidade na
alteração de estado dos objectos pelos quais espera sinalização (no
cenário do parâmetro bWaitAll vir a true)
• Quando o objecto kernel não for mais necessário dever-se-á chamar
a função
BOOL CloseHandle(HANDLE hObject);
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Objecto kernel Event
• O objecto mais simples de todos
• Contém
– um contador de referências (tal como todos os objectos kernel)
– booleano que indica se o reset ao evento é feito automaticamente ou
manualmente quando sinalizado
– booleano que indica se o estado do evento é sinalizado ou não
• Utilização adequada na cooperação entre threads:
– O trabalho a realizar por uma thread depende do trabalho realizado por
outra thread
• Todas as threads na lista de waitables ficam schedulable quando um
evento com reset manual é sinalizado
• Apenas uma thread na lista de waitables fica schedulable quando um
evento com reset automático é sinalizado
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Objecto kernel Event
Funções relevantes
HANDLE CreateEvent(PSECURITY_ATTRIBUTES psa, BOOL bManualReset, BOOL bInitialState, PCTSTR pszName);
HANDLE CreateEventEx(
PSECURITY_ATTRIBUTES psa, PCTSTR pszName, DWORD dwFlags, DWORD dwDesiredAccess); dwFlags ∈ { CREATE_EVENT_INITIAL_SET,
CREATE_EVENT_MANUAL_RESET } HANDLE OpenEvent(
DWORD dwDesiredAccess, BOOL bInherit, PCTSTR pszName); • Todos carecem da chamada a CloseHandle quando o objecto não for mais
necessário
BOOL SetEvent(HANDLE hEvent); // coloca o objecto no estado sinalizado BOOL ResetEvent(HANDLE hEvent); // coloca o objecto no estado não
sinalizado
• Um evento com reset automático é colocado automaticamente no estado não sinalizado quando uma thread conclui a espera com sucesso
BOOL PulseEvent(HANDLE hEvent); // O mesmo que SetEvent seguido de ResetEvent
• Só as threads que estão à espera pelo objecto no momento do Pulse é que ficam schedulable (manual reset); mecanismo de sincronismo pouco usado
6
http://msdn.microsoft.com/en-us/ library/ms686670(v=vs.85).aspx
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Waitable timer kernel objects
HANDLE CreateWaitableTimer(
PSECURITY_ATTRIBUTES psa, BOOL bManualReset,
PCTSTR pszName);
HANDLE OpenWaitableTime(
DWORD dwDesiredAccess, BOOL bInheritHandle,
PCTSTR pszName);
BOOL SetWaitableTimer(
HANDLE hTimer,
const LARGE_INTEGER *pDueTime,
LONG lPeriod,
PTIMEAPCROUTINE pfnCompletionRoutine,
PVOID pvArgToCompletionRoutine,
BOOL bResume);
BOOL CancelWaitableTimer(HANDLE hTimer);
7
>= 0, data absoluta
< 0, tempo relativo à chamada da função
Normalmente a false
Asynchronous Procedure Call
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Objecto kernel Semaphore
• Adequado para contador de recursos
• Para além dos atributos comuns de um objecto kernel, contém 2
valores a 32 bits com sinal
– contador com o número máximo de recursos que o semáforo pode
controlar
– contador com o número corrente de recursos disponíveis
• Regras de sinalização
– contador corrente de recursos maior que zero, o semáforo está
sinalizado
– contador corrente de recursos igual a zero, o semáforo não está
sinalizado
– o sistema nunca permite que o contador corrente de recursos seja
negativo
– o valor do contador corrente de recursos não pode ser nunca maior do
que o valor do contador com o número máximo de recursos
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Objecto kernel Semaphore
Funções relevantes
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa, LONG lInitialCount,
LONG lMaximumCount, PCTSTR pszName);
HANDLE CreateSemaphoreEx(
PSECURITY_ATTRIBUTES psa, LONG lInitialCount,
LONG lMaximumCount, PCTSTR pszName, DWORD dwFlags,
DWORD dwDesiredAccess);
HANDLE OpenSemaphore(
DWORD dwDesiredAccess, BOOL bInherit, PCTSTR pszName);
• Uma thread que solicite um recurso com o contador de recursos
corrente a zero é colocada no estado Wait
• O teste e decremento do contador corrente de recursos é feito de forma
atómica
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
PLONG plPreviousCount);
9Indica quantos recursos estão disponíveis inicialmente
Aceita o argumento NULL
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Objecto kernel Mutex
• Garante exclusão no acesso a um recurso
• Para além dos atributos comuns de um objecto kernel, contém
– identificador da thread que detém o mutex
– um contador de recursões
• Regras de sinalização
– Se o identificador da thread for 0, o mutex não é detido por nenhuma
thread e, portanto, está sinalizado
– Se o identificador da thread for diferente de 0, o mutex é detido por uma
thread e, portanto, não está sinalizado
– Mesmo sem estar sinalizado, o acesso a recursos guardados pelo mutex
pode ser concedido num caso especial: a thread que solicita o recurso é
a mesma que já o detém
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Objecto kernel Mutex
Funções relevantes
HANDLE CreateMutex(PSECURITY_ATTRIBUTES psa, BOOL bInitialOwner, PCTSTR pszName);
HANDLE CreateMutexEx(
PSECURITY_ATTRIBUTES psa , PCTSTR pszName, DWORD dwFlags, DWORD dwDesiredAccess);
HANDLE OpenMutex(
DWORD dwDesiredAccess, BOOL bInheritOwner, PCTSTR pszName);
• Uma thread é colocada no estado Wait quando solicita o recurso guardado pelo mutex se o identificador da thread for diferente de 0 e diferente da thread que solicita o
recurso
• O teste do identificador e incremento do contador de recursões é feito de forma atómica
BOOL ReleaseMutex(HANDLE hMutex);
• Decrementa o contador de recursões se o identificador da thread for igual à thread correntte
– O mutex fica sinalizado se o contador de recursões atingir o valor 0
• Uma função de espera retorna o valor especial WAIT_ABANDONED caso a thread que detém o mutex termine sem o libertar (o SO detecta-o colocando o identificador da thread e o contador de recursões a 0)
11
0 false
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Resumo
Object
When
nonsignaled
When signaled
Successful Wait
Side Effect
Process
When still alive
When terminates
(ExitProcess,
TerminateProcess)
None
Thread
When still alive
When terminates
(ExitProcess,
TerminateProcess)
None
Job
When time’s job
has not expired
When time job
expires
None
File
When I/O request
is pending
When I/O request
completes
None
Console input
No input exists
When input is
available
None
File change
notifications
No file have
changed
When fyle system
detects changes
Reset notification
12
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Resumo (continuação)
Object
When nonsignaled
When signaled
Successful Wait
Side Effect
Auto-reset
event
ResetEvent,
PulseEvent or
successful wait
When SetEvent or
PulseEvent is called
Reset event
Manual-reset
event
ResetEvent or
PulseEvent
When SetEvent or
PulseEvent is called
None
Auto-reset
waitable timer
CancelWaitableTimer
or successful wait
When time comes due
(SetWaitableTimer)
Reset timer
Manual-reset
waitable timer
CancelWaitableTimer
When time comes due
(SetWaitableTimer)
None
Semaphore
Successful wait
When count > 0
(ReleaseSemaphore)
Decrement count
by 1
Mutex
Successful wait
When unowned by a
thread (ReleaseMutex)
Give ownership
to a thread
CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel
Resumo (continuação)
Object
When
nonsignaled
When signaled
Successful Wait
Side Effect
CriticalSection
(user-mode)
Successful wait
((Try)Enter-Critical-Section)
When unowned by
a thread
(LeaveCriticalSecti
on)
Give onweship to
a thread
SWRLock
(user-mode)
Successful wait
(AquireSRWLock(
Exclusive)))
When unowned by
a thread
(ReleaseSRWLoc
k(Exclusive))
Gives onweship to
a thread
Condition variable
(user-mode)
Successful wait
(SleepConditionVa
riable)
When woken up
(Wake(All)Conditio
nVariable)
None
14CCISEL Sistemas Operativos: Sincronização de threads com objectos kernel