İşletim Sistemleri Dr. Binnur Kurt binnur.kurt@gmail.com Omega Eğitim ve Danışmanlık http://www.omegaegitim.com 1 S a y f a
İÇİNDEKİLER 1. İşletim Sistemi 2. Kabuk 3. Prosesler 4. İplikler 5. İplikler Arası Eş Zamanlama 6. Prosesler Arası İletişim 7. İş Sıralama 8. 9. Bellek Yönetimi 10. Dosya Sistemi 11. Soket Haberleşme 2 S a y f a
BÖLÜM 8 Bölümün Amacı Bölüm sonunda aşağıdaki konular öğrenilmiş olacaktır: Semafor o POSIX Semafor o C++11 de Semafor Kullanımı o Java Platformunda Semafor Kullanımı 3 S a y f a
8.1 Giriş 6. bölümde prosesler arası iletişim şekillerini inceledik. Bu bölümde ise prosesler arası kaynak paylaşımı ve eş zamanlama çözümü için kullanılan semafor çözümünü inceleyeceğiz. Semafor programlama 6. bölümde incelediğimiz IPC alt yapısını kullanır ve benzer bir arayüze sahiptir. Bu bölümde önce POSIX tabanlı semafor yapısı incelenecektir. Daha sonra sırasıyla C++11 de ve Java platformunda semafor çözümleri çalışılacaktır. 8.2 POSIX Semafor Birden fazla kaynağı prosesler arasında paylaştırmak gerektiğinde semafor çözümü kullanılır. He proses ihtiyaç duyduğu kaynak kadar kaynak için istekte bulunur. Semafor tamsayı değer saklayan bir nesne olarak düşünülebilir. Bu tamsayının başlangıç değeri kaynak sayısıdır. Semafor üzerinde temel olarak iki tür işlem tanımlıdır: İhtiyaç duyulan kaynak sayısı kadar semaforun değerini azaltmak Kaynakları geri verirken semaforun değerini arttırmak Üç farklı kaynağın bulunduğu ve her bir kaynaktan sırayla 3, 5 ve 10 adet bulunduğu durum için bir POSIX semaforu semget ve semctl çağrılarını kullanarak aşağıdaki şekilde yaratıyoruz: #define NUM_SEMS_IN_GROUP 3 #define RESOURCE1 0 #define RESOURCE2 1 #define RESOURCE3 2 int semid; int numresource1 = 3; int numresource2 = 5; int numresource3 = 10; semid = semget( IPC_PRIVATE, NUM_SEMS_IN_GROUP, IPC_CREAT 0600 ); semctl(semid, RESOURCE1, SETVAL, &numresource1); semctl(semid, RESOURCE2, SETVAL, &numresource2); semctl(semid, RESOURCE3, SETVAL, &numresource3); Bu üç farklı kaynaktan sırayla 2, 3 ve 1 adet kaynak almak için semop çağrısını kullanıyoruz: struct sembuf ops[num_sems_in_group]; ops[0].sem_num = RESOURCE1; ops[0].sem_op = 2; ops[1].sem_num = RESOURCE2; ops[1].sem_op = 3; ops[2].sem_num = RESOURCE3; ops[2].sem_op = 1; 4 S a y f a
ops[0].sem_flg = ops[1].sem_flg = ops[2].sem_flg = WAIT; semop(semid, ops, NUM_SEMS_IN_GROUP); Şimdi daha karmaşık bir problemi çözelim. Ev taşıma hizmeti veren bir firmanın 5 aracı, 12 taşıyıcısı ve 1000 TL ye kadar sigortalanacak taşıma kapasitesi olsun. Kendisine gelen farklı taşıma istekleri için bu kaynakları paylaşımını semafor kullanarak çözelim: Kod 8.1: #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include "utils.h" #define NUM_THREADS 10 #define TIME_BTWN_NEW_THREADS 0.5 #define RUNTIME_RANGE 5.0 #define NUM_SEMS_IN_GROUP 3 #define TRUCK_SEM 0 #define MOVER_SEM 1 #define INSUR_SEM 2 #define NUM_TRUCKS 5 #define NUM_MOVERS 12 #define AMT_INSUR 1000 #define WAIT 0 #define STRING_SIZE 80 #define FALSE 0 #define TRUE (!FALSE) #define STDOUT_FD 1 struct job { int numtrucks; int nummovers; int amtinsurance; jobtable[] = { { 4, 5, 250, { 1, 2, 500, { 3, 5, 1000, { 2, 8, 250, ; int numjobs = sizeof (jobtable) / sizeof (struct job); int semid; extern int errno; void *threadmain(void *); main() { pthread_t threads[num_threads]; 5 S a y f a
int numtrucks = NUM_TRUCKS; int nummovers = NUM_MOVERS; int amtinsur = AMT_INSUR; int count; if ((semid = semget(ipc_private, NUM_SEMS_IN_GROUP, IPC_CREAT 0600)) == -1) { perror("semget"); exit(errno); if ((semctl(semid, TRUCK_SEM, SETVAL, &numtrucks)) (semctl(semid, MOVER_SEM, SETVAL, &nummovers)) (semctl(semid, INSUR_SEM, SETVAL, &amtinsur))) { perror("error initializing semaphores"); goto cleanup; srand48(time(null)); for (count = 0; count < NUM_THREADS; count++) { if (pthread_create(&threads[count], NULL, threadmain, (void *) (count % numjobs))) { perror("error starting reader threads"); goto cleanup; fractsleep(time_btwn_new_threads); for (count = 0; count < NUM_THREADS; count++) { pthread_join(threads[count], (void **) NULL); cleanup: if (semctl(semid, 0, IPC_RMID, NULL)) { perror("semctl IPC_RMID:"); void *threadmain(void * arg) { int jobnum = (int) arg; char string[string_size]; sprintf(string, "Job # %d requesting %d trucks, %d people, $%d000 insurance...\n", jobnum, jobtable[jobnum].numtrucks, jobtable[jobnum].nummovers, jobtable[jobnum].amtinsurance); printwithtime(string); if (reserve(semid, jobtable[jobnum])) { perror("reserve"); return (NULL); sprintf(string, 6 S a y f a
"Job # %d got %d trucks, %d people, %d000 insurance and is running...\n", jobnum, jobtable[jobnum].numtrucks, jobtable[jobnum].nummovers, jobtable[jobnum].amtinsurance); printwithtime(string); fractsleep(drand48() * RUNTIME_RANGE); sprintf(string, "Job # %d done; returning %d trucks, %d people, %d000 insurance...\n", jobnum, jobtable[jobnum].numtrucks, jobtable[jobnum].nummovers, jobtable[jobnum].amtinsurance); printwithtime(string); if (release(semid, jobtable[jobnum])) { perror("release"); int release(int semid, struct job thisjob) { return (playwithsemaphores( semid, thisjob.numtrucks, thisjob.nummovers, thisjob.amtinsurance)); int reserve(int semid, struct job thisjob) { return (playwithsemaphores( semid, -thisjob.numtrucks, -thisjob.nummovers, -thisjob.amtinsurance)); int playwithsemaphores(int semid, int numtrucks, int nummovers, int amtinsurance) { struct sembuf ops[num_sems_in_group]; ops[0].sem_num = TRUCK_SEM; ops[0].sem_op = numtrucks; ops[1].sem_num = MOVER_SEM; ops[1].sem_op = nummovers; ops[2].sem_num = INSUR_SEM; ops[2].sem_op = amtinsurance; ops[0].sem_flg = ops[1].sem_flg = ops[2].sem_flg = WAIT; return (semop(semid, ops, NUM_SEMS_IN_GROUP)); 8.2 C++11 de Semafor Kullanımı C++11 de iplik programlama ve eş zamanlama ile ilgili hazır çözümler gelmiş olsa da semafor çözümünü içermez. Ancak semafor mekanizmasını mutex sınıfını kullanarak gerçekleştirebiliriz: class semaphore { bool hasresource(initializer_list<int> values){ int i=0; for (auto & value : values) if(resources[i++]<value) return false; cerr << "Obtained the resources!" << endl ; return true; 7 S a y f a
public: semaphore(initializer_list<int> inits) { int i=0; for (auto & init : inits) resources.push_back(init); void release(initializer_list<int> values){ unique_lock<mutex> lck(mtx); int i=0; for (auto & value : values) resources[i++] += value; cv.notify_one(); void acquire(initializer_list<int> values){ unique_lock<mutex> lck(mtx); while(!hasresource(values)){ cv.wait(lck); int i=0; for (auto & value : values) resources[i++] -= value; mutex mtx; condition_variable cv; vector<int> resources; ; POSIX semaforları kullanarak çözdüğümüz problemi şimdi yukarıda oluşturduğumuz semaphore sınıfını kullanarak çözmeye çalışalım: int jobs[][3] = { { 4, 5, 250, { 1, 2, 500, { 3, 5, 1000, { 2, 8, 250, ; int main(){ semaphore sem({5, 12, 1000); vector<thread> tasks; auto run= [&sem] (int i,int job[3] ) { sem.acquire({job[0],job[1],job[2]); sem.release({job[0],job[1],job[2]); ; int i=0; for (auto &job : jobs){ tasks.push_back({thread(run,i,job)); ++i; for (auto& task: tasks) task.join(); return 0; 8 S a y f a
8.3 Java Platformunda Semafor Kullanımı Java da semafor programlama için Java SE 5 ile gelen java.util.concurrent paketinde yer alan Semaphore sınıfını kullanıyoruz. Semaphore sınıfını kullanarak semaforu yaratırken kaynak sayısını veriyoruz. Semaphore sınıfında kaynak almak için acquire ve alınan kaynağı geri vermek için release metodları bulunuyor. acquire metodu eğer yeterli sayıda kaynak yok ise, çağrıyı yapan ipliği, diğer iplikler release metodu ile yeterli sayıda kaynak bırakıncaya kadar bir kuyrukta bloke eder. Yukarıda, önce POSIX semaforlarını, daha sonra C++11 kullanarak çözdüğümüz problemi, bu kez Java daki Semaphore sınıfını kullanarak tekrar çözelim: import java.util.arrays; import java.util.concurrent.semaphore; import java.util.concurrent.locks.condition; import java.util.concurrent.locks.reentrantlock; public class TransportationProblem { static int jobs[][] = { { 4, 5, 250, { 1, 2, 500, { 3, 5, 1000, { 2, 8, 250 ; public static void main(string[] args) throws InterruptedException { Thread[] tasks = new Thread[jobs.length]; MultiResource mr = new MultiResource(5, 12, 1000); for (int i = 0; i < tasks.length; ++i) { tasks[i] = new Thread(new Task(mr, jobs[i]), Arrays.toString(jobs[i])); for (Thread task : tasks) task.start(); for (Thread task : tasks) task.join(); class Task implements Runnable { int[] job; MultiResource mr; public Task(MultiResource mr, int[] job) { this.mr = mr; this.job = job; @Override public void run() { try { mr.acquire(job); + " is using the resource " + Arrays.toString(job) + "..."); mr.release(job); + " has relased the resource " + Arrays.toString(job) + "!"); catch (InterruptedException e) { e.printstacktrace(); 9 S a y f a
class MultiResource { private volatile Semaphore[] semaphores; public MultiResource(int... permits) { System.err.println("Initializing the semaphores with permits " + Arrays.toString(permits)); semaphores = new Semaphore[permits.length]; for (int i = 0; i < semaphores.length; ++i) { semaphores[i] = new Semaphore(permits[i], true); public void acquire(int... permits) throws InterruptedException { + " is acquiring the resources " + Arrays.toString(permits)); for (int i = 0; i < permits.length; ++i) { + " acquired the resource(" + (i + 1) + ") " + permits[i]); semaphores[i].acquire(permits[i]); + " acquired the resources " + Arrays.toString(permits) + "...finally!"); public void release(int... permits) throws InterruptedException { + " is releasing " + Arrays.toString(permits) + "..."); for (int i = 0; i < permits.length; ++i) { semaphores[i].release(permits[i]); + " is releasing " + Arrays.toString(permits) + "...done."); 10 S a y f a