> Proses Grupları: Prosesler konusundaki bir diğer kavram da Proses Grup kavramıdır. Bu kavram bir takım prosese tek hamlede sinyal gönderebilmek için oluşturulmuştur. Yine Proses Grup kavramı da ID değerine sahiptir ve buna "Process Group ID" denmektedir. Bu ID değeri ise grup içerisinde bulunan bir prosesin ID değerine eşittir. İş bu prosese ise "Process Group Leader" denir. Yani proses grubunun lideri konumunda olan prosesin ID değeri, o proses grubunun ID değeridir. Genellikle proses grupları, proses grup lideri tarafından oluşturulur fakat liderin o gruptan daha sonra ayrılması da mümkündür. Bu durumda o proses grubunun ID değeri DEĞİŞMEYECEKTİR. Benzer şekilde lider konumunda olan prosesin sonlanması durumunda onun ID değerini işletim sistemi başka yerde kullanmaz çünkü halihazırda bir proses grubu tarafından kullanıldığı için. Diğer yandan proses grubunun sonlandırılması, yani lağvedilmesi, için o proses grubunda hiç bir prosesin kalmaması gerekiyor. Öte yandan "fork" işlemi sırasında proses grup ID değeri de alt prosese, üst proses tarafından, aktarılır. Yani üst proses hangi gruptaysa, alt proses de o grupta olacaktır. Pekiyi bizler bir prosesin içinde bulunduğu proses grubuna ilişkin bilgileri nasıl öğrenebiliriz? Bu noktada devreye "getpgrp" ve "getpgid" isimli POSIX fonksiyonları girecektir. >> "getpgrp" : Fonksiyonu çağıran prosesin "Process Group ID" değerini bize geri döndürür. Fonksiyonun prototipi aşağıdaki gibidir; #include pid_t getpgrp(void); Fonksiyon için herhangi bir hata senaryosu tanımlanmamıştır, yani her zaman için başarılı olur. >> "getpgid" : Herhangi bir prosesin içinde bulunduğu proses grubunun ID değerini bize döndürür. Fonksiyonun prototipi aşağıdaki gibidir; #include pid_t getpgid(pid_t pid); Fonksiyon argüman olarak hangi grupta olduğunu merak ettiğimiz prosesin ID değerini alır. "0" değerini geçersek, fonksiyonu çağıran prosesinkini bize döndürecektir. Fonksiyonumuz hata durumunda "-1" ile geri döner ve "errno" değişkenini uygun değerine çeker. Pekiyi bizler bir proses grubu nasıl oluşturur veya bir prosesin grubunu nasıl değiştirebiliriz? Bu noktada da devreye "setpgid" fonksiyonu girmektedir. >> "setpgid" : Fonksiyonun prototipi aşağıdaki gibidir; #include int setpgid(pid_t pid, pid_t pgid); Fonksiyonun birinci parametresine Proses Grup ID değerini değiştirmek istediğimiz prosesin ID değerini, ikinci parametresine de hedef Proses Grup ID değerini geçiyoruz. Böylelikle prosesimiz başka bir gruba dahil olacaktır. Eğer bu iki parametreye aynı değeri geçersek, o ID değerinde yeni bir proses grubu oluşturulur ve prosesimiz de grubun lideri olur. Tabii bu işlemleri aynı oturum("session") içerisinde, prosesimizin uygun önceliğe sahip olup olmadığına bakılmaksızın, kendimiz ve/veya alt proseslerimiz için gerçekleştirebiliriz. Fakat buradaki kritik nokta ise şudur; alt prosesimiz "exec" işlemi uyguladıktan sonra artık onun proses grup ID değerini DEĞİŞTİREMEYİZ. Oturum("session") kavramına ilerleyen zamanlarda değinilecektir. Son olarak fonksiyonun birinci parametresine "0" geçilmesi, bu fonksiyonu çağıran proses; ikinci parametresine "0" geçilmesi, birinci parametresine geçilen proses kastedilmektedir. Dolayısıyla aşağıdaki çağrılar aynı anlama gelmektedir; setpgid(getpid(), getpid()); setpgid(0, getpid()); setpgid(getpid(), 0); setpgid(0, 0); İşte kabuk program(lar)ı da aslında bu şekilde çalışmaktadır. Yani "shell" programı önce "fork" yapar. Üst ya da alt proses içerisinde "setpgid" fonksiyonunu çağırır ve yeni bir proses grubu oluşturup, alt prosesin bu grubun lideri olmasını sağlar. * Örnek 1, "shell" programı üzerinden "|" kullanarak birden fazla komut çalıştırdığımızı varsayalım: "ls -l | grep "sample" Bu çağrı sonucunda "shell" programı "ls" ve "grep" programları için "fork" işlemi yapacaktır. İlk "fork" çağrısı "ls" için yapılacağından, oluşturulacak proses grubunun lideri de "ls" olacaktır. Eğer "ls" ve "grep" programları da kendi içerisinde "fork" yapıyorsa, oluşan bu yeni alt prosesler de yine aynı proses grubuna eklenecektir. Buradaki kilit nokta tek bir komut satırında birden fazla program çalıştırılmasıdır. * Örnek 2, // Terminal - I: "cat | grep "sample" " komutunu çalıştıralım. // Termianl - II: "ps -t pts/0 -o pid, ppid, pgid,cmd" kabuk komutunu çalıştırdığımız zaman, "Terminal - I" tarafından çalıştırılan prosesleri göreceğiz: PID PPID PGID CMD 34667 34658 34667 bash 49458 34667 49458 cat 49459 34667 49458 grep Görüleceği üzere "cat" ve "grep" prosesleri için tek bir proses grubu oluşturulmuş. * Örnek 3.0, #include #include #include #include #include void exit_sys(const char* msg); int main(int argc, char** argv) { /* # OUTPUT # Parent Process ID: 53 Grandparent Process ID: 52 Parent Process Group ID: 53 Child Process ID: 57 Parent Process ID: 53 Child Process Group ID: 57 */ pid_t pid, pgid; if ((pid = fork()) == -1) exit_sys("fork"); if (pid != 0) { /* Parent Process */ printf("Parent Process ID: %jd\n", (intmax_t)getpid()); printf("Grandparent Process ID: %jd\n", (intmax_t)getppid()); pgid = getpgrp(); printf("Parent Process Group ID: %jd\n", (intmax_t)pgid); if (waitpid(pid, NULL, 0) == -1) exit_sys("waitpid"); } else { /* Child Process */ sleep(1); // Yeni bir proses grubu oluşturulacak. if (setpgid(getpid(), getpid()) == -1) exit_sys("setpgid"); printf("Child Process ID: %jd\n", (intmax_t)getpid()); printf("Parent Process ID: %jd\n", (intmax_t)getppid()); pgid = getpgrp(); printf("Child Process Group ID: %jd\n", (intmax_t)pgid); } return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 3.1, #include #include #include #include #include void exit_sys(const char* msg); int main(int argc, char** argv) { /* # OUTPUT # Parent Process ID: 614 Grandparent Process ID: 613 Parent Process Group ID: 614 Child Process ID: 618 Parent Process ID: 614 Child Process Group ID: 614 */ pid_t pid, pgid; if ((pid = fork()) == -1) exit_sys("fork"); if (pid != 0) { /* Parent Process */ printf("Parent Process ID: %jd\n", (intmax_t)getpid()); printf("Grandparent Process ID: %jd\n", (intmax_t)getppid()); pgid = getpgrp(); printf("Parent Process Group ID: %jd\n", (intmax_t)pgid); if (waitpid(pid, NULL, 0) == -1) exit_sys("waitpid"); } else { /* Child Process */ sleep(1); printf("Child Process ID: %jd\n", (intmax_t)getpid()); printf("Parent Process ID: %jd\n", (intmax_t)getppid()); pgid = getpgrp(); printf("Child Process Group ID: %jd\n", (intmax_t)pgid); } return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 4, Aşağıdaki programda ise "Ctrl+C" yaparak proses grubundaki proseslere "SIGINT" sinyali gönderilmiştir. #include #include #include #include #include #include void sig_handler(int sno); void exit_sys(const char* msg); int main(int argc, char** argv) { /* # OUTPUT # Parent Process ID: 230 Grandparent Process ID: 229 Parent Process Group ID: 230 Child Process ID: 234 Parent Process ID: 230 Child Process Group ID: 230 :> ^C waitpid: Interrupted system call SIGINT in the Process: 234 SIGINT in the Process: 230 */ struct sigaction sa; sa.sa_handler = sig_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGINT, &sa, NULL) == -1) exit_sys("sigaction"); pid_t pid, pgid; if ((pid = fork()) == -1) exit_sys("fork"); if (pid != 0) { /* Parent Process */ printf("Parent Process ID: %jd\n", (intmax_t)getpid()); printf("Grandparent Process ID: %jd\n", (intmax_t)getppid()); pgid = getpgrp(); printf("Parent Process Group ID: %jd\n", (intmax_t)pgid); if (waitpid(pid, NULL, 0) == -1) exit_sys("waitpid"); } else { /* Child Process */ sleep(1); printf("Child Process ID: %jd\n", (intmax_t)getpid()); printf("Parent Process ID: %jd\n", (intmax_t)getppid()); pgid = getpgrp(); printf("Child Process Group ID: %jd\n", (intmax_t)pgid); pause(); } return 0; } void sig_handler(int sno) { printf("SIGINT in the Process: %jd\n", (intmax_t)getpid()); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } Şu da belirtilmelidir ki "thread" ler için herhangi bir proses grup kavramı YOKTUR. Proses Grup kavramı yalnızca prosesler temelinde mevcuttur. Yani bütün "thread" ler içerisinde yapılan "getgrp" çağrıları aynı sonucu verecektir.