Süreciniz bir sinyal yakalayıcının çalışmasından hemen önce aynı türden çok sayıda sinyal alırsa, yakalayıcı tek bir sinyal alınmış gibi sadece bir kere çalıştırılabilir. Gerçekte ise, sinyaller tek bir sinyal içine katıştırılmış olur. Bu durum, sinyal engellendiğinde ya da çok süreçli bir ortam da sistemin başka bir süreçle meşgul olduğı bir sırada ortaya çıkabilir. Bu, örneğin, bir sinyal yakalayıcıyı bir sinyal sayacı olarak kullanamayacağınız anlamına gelir. Ayırdına varacağınız tek şey, bir kerede en azından bir sinyal almış olduğunuz olacaktır.
Aşağıda, alt süreç tarafından üretilen sinyallerin alınan sinyallerin sayısına eşit olmayışını telafi eden bir SIGCHLD yakalayıcısı örneği verilmiştir. Burada yazılımın, alt süreçlerin izini sürmek için bir yapı zinciri kullandığı varsayılmıştır:
struct process
{
struct process *next;
/* Bu sürecin süreç kimliği. */
int pid;
/* Bu süreçten gelen çıktıların yönlendirileceği
uçbirim ya da boru tanımlayıcı. */
int input_descriptor;
/* Bu süreç durdurulursa ya da sonlandırılırsa
değişkenin değeri sıfırdan farklı olacak. */
sig_atomic_t have_status;
/* Bu sürecin durumu; çalışıyorsa sıfırdır,
aksi takdirde waitpid'deki durum değeridir. */
int status;
};
struct process *process_list;
Bu örnek, hemen öncesinde bazı sinyallerin alınmasına bağlı olarak bir değişken de kullanıyor. Her seferinde yazılımın sonunda bu sıfırlanıyor.
/* Sıfırdan farklı bir değer alt sürecin durumunun
değiştiği anlamına gelir. Bu durumla ilgili ayrıntılar
için process_list'e bakılmalı. */
int process_status_change;
Eylemci:
void
sigchld_handler (int signo)
{
int old_errno = errno;
while (1) {
register int pid;
int w;
struct process *p;
/* Tanımlanabilir bir sonuç alana kadar sorguyu sürdürüyoruz. */
do
{
errno = 0;
pid = waitpid (WAIT_ANY, &w, WNOHANG | WUNTRACED);
}
while (pid <= 0 && errno == EINTR);
if (pid <= 0) {
/* Bir alt süreç kalmamışsa çıkabiliriz. */
errno = old_errno;
return;
}
/* Sinyal gönderen süreci bulalım ve durumunu kaydedelim. */
for (p = process_list; p; p = p->next)
if (p->pid == pid) {
p->status = w;
/* Durum alanınnı bir veri içerdiğini belirtelim.
Bunu onu sakladıktan sonra yapıyoruz. */
p->have_status = 1;
/* Süreç sonlandırılmışsa çıktısını beklemekten vazgeçiyoruz. */
if (WIFSIGNALED (w) || WIFEXITED (w))
if (p->input_descriptor)
FD_CLR (p->input_descriptor, &input_wait_mask);
/* Yazılım arasıra bu değişkene süreç listesinde yeni bir
süreç var mı diye bakmalı. */
++process_status_change;
}
/* Bize söyleyecek birşeyleri var mı diye tekrar dönüp tüm
süreçlere bakalım. */
}
}
process_status_change değişkenini denetlemek için bir yöntem:
if (process_status_change) {
struct process *p;
process_status_change = 0;
for (p = process_list; p; p = p->next)
if (p->have_status) {
… p->status incelemesi …
}
}
Listeyi incelemeye başlamadan önce seçeneğin temizlenmesi hayati önemdedir; aksi takdirde, seçeneğin temizlenmesinden önce bir sinyal alınırsa ve süreç listesinin ilgili elemanı etkinse, bu seçenekle ilgili olarak sinyal hakkında bir uyarı alınamayacaktır. Bu sorundan kaçınmak için listeyi taramaya başlamadan önce seçeneği temizlemeniz gerekir; bazı işlemleri doğru sırada yapmak önemlidir.
Döngüde
p-status alanı incelenerek, sürecin durumu hakkında bilgi edinilmeye çalışılır.
p->have_status etkin bir değere sahipse, süreç durdurulmuş ya da sonlandırılmıştır; değilse, yazılım tekrar uyarı alana kadar durdurulamamış ya da sonlandırılamamıştır. Bir değişkene erişim sırasındaki kesmelerin kaydedilmesi hakkında daha fazla bilgi için
Atomsal Kullanım Şekilleri bölümüne bakınız.
Bşaka bir yol da, sinyal yakalayıcının son sınamadan beri çalıştırılıp çalıştırılmadığına bakmaktır. Bu teknikte, sinyal yakalayıcının dışında değiştirilmeyen bir sayaç kulanılır. Sayacı sıfırlamak yerine, yazılım sayacın son değerini hatırlayarak önceki sınamadan beri bir değişiklik olup olmadığına bakar. Bu yöntemin bir faydası da, yazılımın parçalarının birbirinden bağımsız olarak denetlenebilmesidir.
sig_atomic_t process_status_change;
sig_atomic_t last_process_status_change;
…
{
sig_atomic_t prev = last_process_status_change;
last_process_status_change = process_status_change;
if (last_process_status_change != prev) {
struct process *p;
for (p = process_list; p; p = p->next)
if (p->have_status) {
… p->status incelemesi…
}
}
}