GNU/Linux >> Belajar Linux >  >> Linux

Komunikasi antar-proses di Linux:Penyimpanan bersama

Ini adalah artikel pertama dalam seri tentang komunikasi antarproses (IPC) di Linux. Seri ini menggunakan contoh kode dalam C untuk memperjelas mekanisme IPC berikut:

  • File yang dibagikan
  • Memori bersama (dengan semafor)
  • Pipa (bernama dan tanpa nama)
  • Antrian pesan
  • Soket
  • Sinyal

Artikel ini mengulas beberapa konsep inti sebelum beralih ke dua mekanisme pertama:file bersama dan memori bersama.

Konsep inti

Sebuah proses adalah program yang sedang dieksekusi, dan setiap proses memiliki ruang alamatnya sendiri, yang terdiri dari lokasi memori yang diizinkan untuk diakses oleh proses. Sebuah proses memiliki satu atau lebih utas eksekusi, yang merupakan urutan instruksi yang dapat dieksekusi:sebuah single-threaded proses hanya memiliki satu utas, sedangkan multi-utas proses memiliki lebih dari satu utas. Utas dalam suatu proses berbagi berbagai sumber daya, khususnya, ruang alamat. Dengan demikian, utas dalam suatu proses dapat berkomunikasi secara langsung melalui memori bersama, meskipun beberapa bahasa modern (mis., Go) mendorong pendekatan yang lebih disiplin seperti penggunaan saluran yang aman untuk utas. Yang menarik di sini adalah bahwa proses yang berbeda, secara default, tidak berbagi memori.

Ada berbagai cara untuk meluncurkan proses yang kemudian berkomunikasi, dan dua cara mendominasi dalam contoh berikut:

  • Terminal digunakan untuk memulai satu proses, dan mungkin terminal yang berbeda digunakan untuk memulai yang lain.
  • Fungsi sistem garpu dipanggil dalam satu proses (induk) untuk menelurkan proses lain (anak).

Contoh pertama mengambil pendekatan terminal. Contoh kode tersedia dalam file ZIP di situs web saya.

File bersama

Pemrogram terlalu akrab dengan akses file, termasuk banyak jebakan (file tidak ada, izin file yang buruk, dan sebagainya) yang menimpa penggunaan file dalam program. Meskipun demikian, file bersama mungkin merupakan mekanisme IPC yang paling dasar. Pertimbangkan kasus yang relatif sederhana di mana satu proses (produser ) membuat dan menulis ke file, dan proses lain (konsumen ) membaca dari file yang sama ini:

         writes  +-----------+  reads
producer-------->| disk file |<-------consumer
                 +-----------+

Tantangan nyata dalam menggunakan mekanisme IPC ini adalah kondisi balapan mungkin timbul:produsen dan konsumen mungkin mengakses file pada waktu yang sama persis, sehingga membuat hasilnya tidak pasti. Untuk menghindari kondisi balapan, file harus dikunci sedemikian rupa untuk mencegah konflik antara tulis operasi dan operasi lainnya, baik baca atau tulis . API penguncian di pustaka sistem standar dapat diringkas sebagai berikut:

  • Produser harus mendapatkan kunci eksklusif pada file sebelum menulis ke file. Sebuah eksklusif kunci dapat dipegang oleh satu proses paling banyak, yang mengesampingkan kondisi balapan karena tidak ada proses lain yang dapat mengakses file sampai kunci dilepaskan.
  • Konsumen harus mendapatkan setidaknya kunci bersama pada file sebelum membaca dari file. Beberapa pembaca dapat mengadakan berbagi mengunci pada saat yang sama, tetapi tidak ada penulis dapat mengakses file bahkan ketika satu pembaca memegang kunci bersama.

Kunci bersama meningkatkan efisiensi. Jika satu proses hanya membaca file dan tidak mengubah isinya, tidak ada alasan untuk mencegah proses lain melakukan hal yang sama. Menulis, bagaimanapun, jelas menuntut akses eksklusif ke file.

Pustaka I/O standar menyertakan fungsi utilitas bernama fcntl yang dapat digunakan untuk memeriksa dan memanipulasi kunci eksklusif dan bersama pada file. Fungsi ini bekerja melalui deskriptor file , nilai integer non-negatif yang, dalam suatu proses, mengidentifikasi file. (Descriptor file yang berbeda dalam proses yang berbeda dapat mengidentifikasi file fisik yang sama.) Untuk penguncian file, Linux menyediakan fungsi library flock , yang merupakan pembungkus tipis di sekitar fcntl . Contoh pertama menggunakan fcntl berfungsi untuk mengekspos detail API.

Contoh 1. produser program

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define FileName "data.dat"
#define DataString "Now is the winter of our discontent\nMade glorious summer by this sun of York\n"

void report_and_exit(const char* msg) {
  perror(msg);
  exit(-1); /* EXIT_FAILURE */
}

int main() {
  struct flock lock;
  lock.l_type = F_WRLCK;    /* read/write (exclusive versus shared) lock */
  lock.l_whence = SEEK_SET; /* base for seek offsets */
  lock.l_start = 0;         /* 1st byte in file */
  lock.l_len = 0;           /* 0 here means 'until EOF' */
  lock.l_pid = getpid();    /* process id */

  int fd; /* file descriptor to identify a file within a process */
  if ((fd = open(FileName, O_RDWR | O_CREAT, 0666)) < 0)  /* -1 signals an error */
    report_and_exit("open failed...");

  if (fcntl(fd, F_SETLK, &lock) < 0) /** F_SETLK doesn't block, F_SETLKW does **/
    report_and_exit("fcntl failed to get lock...");
  else {
    write(fd, DataString, strlen(DataString)); /* populate data file */
    fprintf(stderr, "Process %d has written to data file...\n", lock.l_pid);
  }

  /* Now release the lock explicitly. */
  lock.l_type = F_UNLCK;
  if (fcntl(fd, F_SETLK, &lock) < 0)
    report_and_exit("explicit unlocking failed...");

  close(fd); /* close the file: would unlock if needed */
  return 0;  /* terminating the process would unlock as well */
}

Langkah-langkah utama di produser program di atas dapat diringkas sebagai berikut:

  • Program mendeklarasikan variabel bertipe struct berkelompok , yang mewakili kunci, dan menginisialisasi lima bidang struktur. Inisialisasi pertama:
    lock.l_type = F_WRLCK; /* exclusive lock */

    membuat kunci menjadi eksklusif (baca-tulis ) daripada yang dibagikan (hanya-baca ) kunci. Jika produser mendapatkan kunci, maka tidak ada proses lain yang dapat menulis atau membaca file sampai produser melepaskan kunci, baik secara eksplisit dengan panggilan yang sesuai ke fcntl atau secara implisit dengan menutup file. (Saat proses berakhir, semua file yang dibuka akan ditutup secara otomatis, dengan demikian kunci akan terlepas.)

  • Program kemudian menginisialisasi bidang yang tersisa. Efek utamanya adalah seluruh file yang akan dikunci. Namun, API penguncian hanya mengizinkan byte yang ditentukan untuk dikunci. Misalnya, jika file berisi beberapa catatan teks, maka satu catatan (atau bahkan sebagian dari catatan) dapat dikunci dan sisanya dibiarkan tidak terkunci.
  • Panggilan pertama ke fcntl :
    if (fcntl(fd, F_SETLK, &lock) < 0)

    mencoba mengunci file secara eksklusif, memeriksa apakah panggilan berhasil. Secara umum, fcntl fungsi mengembalikan -1 (karenanya, kurang dari nol) untuk menunjukkan kegagalan. Argumen kedua F_SETLK berarti panggilan ke fcntl apakah tidak blok:fungsi segera kembali, baik memberikan kunci atau menunjukkan kegagalan. Jika bendera F_SETLKW (P pada akhirnya adalah untuk menunggu ) digunakan sebagai gantinya, panggilan ke fcntl akan memblokir sampai mendapatkan kunci itu mungkin. Dalam panggilan ke fcntl , argumen pertama fd adalah deskriptor file, argumen kedua menentukan tindakan yang akan diambil (dalam hal ini, F_SETLK untuk menyetel kunci), dan argumen ketiga adalah alamat struktur kunci (dalam hal ini, &kunci ).

  • Jika produser mendapatkan kunci, program menulis dua catatan teks ke file.
  • Setelah menulis ke file, produser mengubah l_type struktur kunci bidang ke membuka nilai:
    lock.l_type = F_UNLCK;

    dan menelepon fcntl untuk melakukan operasi pembukaan kunci. Program selesai dengan menutup file dan keluar.

Contoh 2. konsumen program

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#define FileName "data.dat"

void report_and_exit(const char* msg) {
  perror(msg);
  exit(-1); /* EXIT_FAILURE */
}

int main() {
  struct flock lock;
  lock.l_type = F_WRLCK;    /* read/write (exclusive) lock */
  lock.l_whence = SEEK_SET; /* base for seek offsets */
  lock.l_start = 0;         /* 1st byte in file */
  lock.l_len = 0;           /* 0 here means 'until EOF' */
  lock.l_pid = getpid();    /* process id */

  int fd; /* file descriptor to identify a file within a process */
  if ((fd = open(FileName, O_RDONLY)) < 0)  /* -1 signals an error */
    report_and_exit("open to read failed...");

  /* If the file is write-locked, we can't continue. */
  fcntl(fd, F_GETLK, &lock); /* sets lock.l_type to F_UNLCK if no write lock */
  if (lock.l_type != F_UNLCK)
    report_and_exit("file is still write locked...");

  lock.l_type = F_RDLCK; /* prevents any writing during the reading */
  if (fcntl(fd, F_SETLK, &lock) < 0)
    report_and_exit("can't get a read-only lock...");

  /* Read the bytes (they happen to be ASCII codes) one at a time. */
  int c; /* buffer for read bytes */
  while (read(fd, &c, 1) > 0)    /* 0 signals EOF */
    write(STDOUT_FILENO, &c, 1); /* write one byte to the standard output */

  /* Release the lock explicitly. */
  lock.l_type = F_UNLCK;
  if (fcntl(fd, F_SETLK, &lock) < 0)
    report_and_exit("explicit unlocking failed...");

  close(fd);
  return 0;
}

konsumen program lebih rumit dari yang diperlukan untuk menyoroti fitur-fitur API penguncian. Khususnya, konsumen program pertama-tama memeriksa apakah file dikunci secara eksklusif dan baru kemudian mencoba mendapatkan kunci bersama. Kode yang relevan adalah:

lock.l_type = F_WRLCK;
...
fcntl(fd, F_GETLK, &lock); /* sets lock.l_type to F_UNLCK if no write lock */
if (lock.l_type != F_UNLCK)
  report_and_exit("file is still write locked...");

F_GETLK operasi yang ditentukan dalam fcntl panggilan memeriksa kunci, dalam hal ini, kunci eksklusif diberikan sebagai F_WRLCK dalam pernyataan pertama di atas. Jika kunci yang ditentukan tidak ada, maka fcntl panggilan secara otomatis mengubah bidang jenis kunci menjadi F_UNLCK untuk menunjukkan fakta ini. Jika file dikunci secara eksklusif, konsumen berakhir. (Versi program yang lebih kuat mungkin memiliki konsumen tidur sedikit dan coba lagi beberapa kali.)

Jika file saat ini tidak terkunci, maka konsumen mencoba untuk mendapatkan (hanya-baca . yang dibagikan ) kunci (F_RDLCK ). Untuk mempersingkat program, F_GETLK telepon ke fcntl dapat dijatuhkan karena F_RDLCK panggilan akan gagal jika baca-tulis kunci sudah dipegang oleh beberapa proses lain. Ingatlah bahwa hanya-baca lock tidak mencegah proses lain menulis ke file, tetapi mengizinkan proses lain untuk membaca dari file. Singkatnya, berbagi kunci dapat dipegang oleh beberapa proses. Setelah mendapatkan kunci bersama, konsumen program membaca byte satu per satu dari file, mencetak byte ke output standar, melepaskan kunci, menutup file, dan mengakhiri.

Berikut adalah output dari dua program yang diluncurkan dari terminal yang sama dengan % sebagai prompt baris perintah:

% ./producer
Process 29255 has written to data file...

% ./consumer
Now is the winter of our discontent
Made glorious summer by this sun of York

Dalam contoh kode pertama ini, data yang dibagikan melalui IPC adalah teks:dua baris dari drama Shakespeare Richard III . Namun, konten file yang dibagikan dapat berupa byte yang banyak dan sewenang-wenang (misalnya, film digital), yang membuat berbagi file menjadi mekanisme IPC yang sangat fleksibel. Kelemahannya adalah akses file relatif lambat, baik aksesnya melibatkan membaca atau menulis. Seperti biasa, pemrograman datang dengan pengorbanan. Contoh berikutnya memiliki keunggulan IPC melalui memori bersama, bukan file bersama, dengan peningkatan kinerja yang sesuai.

Memori bersama

Sistem Linux menyediakan dua API terpisah untuk memori bersama:API Sistem V lama dan API POSIX yang lebih baru. Namun, API ini tidak boleh dicampur dalam satu aplikasi. Kelemahan dari pendekatan POSIX adalah bahwa fitur masih dalam pengembangan dan bergantung pada versi kernel yang diinstal, yang berdampak pada portabilitas kode. Misalnya, POSIX API, secara default, mengimplementasikan memori bersama sebagai file yang dipetakan memori :untuk segmen memori bersama, sistem menyimpan file cadangan dengan konten yang sesuai. Memori bersama di bawah POSIX dapat dikonfigurasi tanpa file pendukung, tetapi ini dapat memengaruhi portabilitas. Contoh saya menggunakan POSIX API dengan file pendukung, yang menggabungkan manfaat akses memori (kecepatan) dan penyimpanan file (kegigihan).

Contoh memori bersama memiliki dua program, bernama memwriter dan pembaca , dan menggunakan semafor untuk mengoordinasikan akses mereka ke memori bersama. Kapan pun memori bersama muncul bersama penulis , baik dalam multi-pemrosesan atau multi-threading, begitu juga risiko kondisi balapan berbasis memori; karenanya, semaphore digunakan untuk mengoordinasikan (menyinkronkan) akses ke memori bersama.

penulis anggota program harus dimulai terlebih dahulu di terminalnya sendiri. pembaca program kemudian dapat dimulai (dalam belasan detik) di terminalnya sendiri. Keluaran dari memreader adalah:

This is the way the world ends...

Lebih banyak sumber daya Linux

  • Lembar contekan perintah Linux
  • Lembar contekan perintah Linux tingkat lanjut
  • Kursus online gratis:Ikhtisar Teknis RHEL
  • Lembar contekan jaringan Linux
  • Lembar contekan SELinux
  • Lembar contekan perintah umum Linux
  • Apa itu container Linux?
  • Artikel Linux terbaru kami

Setiap file sumber memiliki dokumentasi di bagian atas yang menjelaskan tanda tautan yang akan disertakan selama kompilasi.

Mari kita mulai dengan ulasan tentang cara kerja semaphore sebagai mekanisme sinkronisasi. Sebuah semaphore umum juga disebut counting semaphore , karena memiliki nilai (biasanya diinisialisasi ke nol) yang dapat ditambah. Pertimbangkan sebuah toko yang menyewakan sepeda, dengan seratus stok, dengan program yang digunakan pegawai untuk melakukan persewaan. Setiap kali menyewa sepeda, semaphore bertambah satu; ketika sepeda dikembalikan, semaphore dikurangi satu. Penyewaan dapat berlanjut hingga nilainya mencapai 100 tetapi kemudian harus dihentikan hingga setidaknya satu sepeda dikembalikan, sehingga mengurangi semaphore menjadi 99.

Sebuah semafor biner adalah kasus khusus yang hanya membutuhkan dua nilai:0 dan 1. Dalam situasi ini, semaphore bertindak sebagai mutex :sebuah konstruksi pengecualian bersama. Contoh shared-memory menggunakan semaphore sebagai mutex. Ketika nilai semaphore adalah 0, memwriter sendiri yang dapat mengakses memori bersama. Setelah menulis, proses ini menambah nilai semaphore, sehingga memungkinkan memreader untuk membaca memori bersama.

Contoh 3. Kode sumber untuk memwriter proses

/** Compilation: gcc -o memwriter memwriter.c -lrt -lpthread **/
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include "shmem.h"

void report_and_exit(const char* msg) {
  perror(msg);
  exit(-1);
}

int main() {
  int fd = shm_open(BackingFile,      /* name from smem.h */
                    O_RDWR | O_CREAT, /* read/write, create if needed */
                    AccessPerms);     /* access permissions (0644) */
  if (fd < 0) report_and_exit("Can't open shared mem segment...");

  ftruncate(fd, ByteSize); /* get the bytes */

  caddr_t memptr = mmap(NULL,       /* let system pick where to put segment */
                        ByteSize,   /* how many bytes */
                        PROT_READ | PROT_WRITE, /* access protections */
                        MAP_SHARED, /* mapping visible to other processes */
                        fd,         /* file descriptor */
                        0);         /* offset: start at 1st byte */
  if ((caddr_t) -1  == memptr) report_and_exit("Can't get segment...");

  fprintf(stderr, "shared mem address: %p [0..%d]\n", memptr, ByteSize - 1);
  fprintf(stderr, "backing file:       /dev/shm%s\n", BackingFile );

  /* semaphore code to lock the shared mem */
  sem_t* semptr = sem_open(SemaphoreName, /* name */
                           O_CREAT,       /* create the semaphore */
                           AccessPerms,   /* protection perms */
                           0);            /* initial value */
  if (semptr == (void*) -1) report_and_exit("sem_open");

  strcpy(memptr, MemContents); /* copy some ASCII bytes to the segment */

  /* increment the semaphore so that memreader can read */
  if (sem_post(semptr) < 0) report_and_exit("sem_post");

  sleep(12); /* give reader a chance */

  /* clean up */
  munmap(memptr, ByteSize); /* unmap the storage */
  close(fd);
  sem_close(semptr);
  shm_unlink(BackingFile); /* unlink from the backing file */
  return 0;
}

Berikut adalah ikhtisar tentang cara penulis anggota dan pembaca program berkomunikasi melalui memori bersama:

  • Si penulis anggota program, yang ditunjukkan di atas, memanggil shm_open berfungsi untuk mendapatkan deskriptor file untuk file pendukung yang dikoordinasikan oleh sistem dengan memori bersama. Pada titik ini, tidak ada memori yang dialokasikan. Panggilan berikutnya ke fungsi bernama ftruncate :
    ftruncate(fd, ByteSize); /* get the bytes */

    mengalokasikan ByteSize byte, dalam hal ini, 512 byte sederhana. penulis anggota dan pembaca program hanya mengakses memori bersama, bukan file pendukung. Sistem bertanggung jawab untuk menyinkronkan memori bersama dan file cadangan.

  • Si penulis anggota lalu panggil mmap function:
    caddr_t memptr = mmap(NULL,       /* let system pick where to put segment */
                          ByteSize,   /* how many bytes */
                          PROT_READ | PROT_WRITE, /* access protections */
                          MAP_SHARED, /* mapping visible to other processes */
                          fd,         /* file descriptor */
                          0);         /* offset: start at 1st byte */

    untuk mendapatkan pointer ke memori bersama. (pembaca membuat panggilan serupa.) Jenis penunjuk caddr_t dimulai dengan c untuk panggilan , fungsi sistem yang menginisialisasi penyimpanan yang dialokasikan secara dinamis ke nol. penulis anggota menggunakan memptr untuk tulis nanti operasi, menggunakan perpustakaan strcpy (salinan string).

  • Pada titik ini, penulis anggota siap untuk menulis, tetapi pertama-tama membuat semaphore untuk memastikan akses eksklusif ke memori bersama. Kondisi balapan akan terjadi jika penulis anggota sedang menulis saat memreader sedang membaca. Jika panggilan ke sem_open berhasil:
    sem_t* semptr = sem_open(SemaphoreName, /* name */
                             O_CREAT,       /* create the semaphore */
                             AccessPerms,   /* protection perms */
                             0);            /* initial value */

    maka penulisan dapat dilanjutkan. SemaphoreName (nama unik apa pun yang tidak kosong dapat digunakan) mengidentifikasi semaphore di memwriter dan pembaca . Nilai awal nol memberikan pencipta semaphore, dalam hal ini, memwriter , hak untuk melanjutkan, dalam hal ini, ke menulis operasi.

  • Setelah menulis, penulis anggota menambah nilai semaphore menjadi 1:
    if (sem_post(semptr) < 0) ..

    dengan panggilan ke sem_post fungsi. Menambah semaphore melepaskan kunci mutex dan mengaktifkan memreader untuk melakukan membaca operasi. Untuk ukuran yang baik, penulis anggota juga membuka peta memori bersama dari memwriter ruang alamat:

    munmap(memptr, ByteSize); /* unmap the storage *

    Ini akan memblokir penulis anggota dari akses lebih lanjut ke memori bersama.

Contoh 4. Kode sumber untuk memreader proses

/** Compilation: gcc -o memreader memreader.c -lrt -lpthread **/
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include "shmem.h"

void report_and_exit(const char* msg) {
  perror(msg);
  exit(-1);
}

int main() {
  int fd = shm_open(BackingFile, O_RDWR, AccessPerms);  /* empty to begin */
  if (fd < 0) report_and_exit("Can't get file descriptor...");

  /* get a pointer to memory */
  caddr_t memptr = mmap(NULL,       /* let system pick where to put segment */
                        ByteSize,   /* how many bytes */
                        PROT_READ | PROT_WRITE, /* access protections */
                        MAP_SHARED, /* mapping visible to other processes */
                        fd,         /* file descriptor */
                        0);         /* offset: start at 1st byte */
  if ((caddr_t) -1 == memptr) report_and_exit("Can't access segment...");

  /* create a semaphore for mutual exclusion */
  sem_t* semptr = sem_open(SemaphoreName, /* name */
                           O_CREAT,       /* create the semaphore */
                           AccessPerms,   /* protection perms */
                           0);            /* initial value */
  if (semptr == (void*) -1) report_and_exit("sem_open");

  /* use semaphore as a mutex (lock) by waiting for writer to increment it */
  if (!sem_wait(semptr)) { /* wait until semaphore != 0 */
    int i;
    for (i = 0; i < strlen(MemContents); i++)
      write(STDOUT_FILENO, memptr + i, 1); /* one byte at a time */
    sem_post(semptr);
  }

  /* cleanup */
  munmap(memptr, ByteSize);
  close(fd);
  sem_close(semptr);
  unlink(BackingFile);
  return 0;
}

Di kedua memwriter dan pembaca program, fungsi memori bersama yang menjadi perhatian utama adalah shm_open dan mmap :jika berhasil, panggilan pertama mengembalikan deskriptor file untuk file pendukung, yang kemudian digunakan oleh panggilan kedua untuk mendapatkan penunjuk ke segmen memori bersama. Panggilan ke shm_open serupa di kedua program kecuali memwriter program membuat memori bersama, sedangkan memreader hanya mengakses memori yang sudah dibuat ini:

int fd = shm_open(BackingFile, O_RDWR | O_CREAT, AccessPerms); /* memwriter */
int fd = shm_open(BackingFile, O_RDWR, AccessPerms);           /* memreader */

Dengan deskriptor file di tangan, panggilan ke mmap sama:

caddr_t memptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

Argumen pertama untuk mmap adalah NULL , yang berarti bahwa sistem menentukan tempat untuk mengalokasikan memori dalam ruang alamat virtual. Dimungkinkan (tetapi rumit) untuk menentukan alamat sebagai gantinya. MAP_SHARED flag menunjukkan bahwa memori yang dialokasikan dapat dibagikan di antara proses, dan argumen terakhir (dalam hal ini, nol) berarti bahwa offset untuk memori bersama harus menjadi byte pertama. ukuran argumen menentukan jumlah byte yang akan dialokasikan (dalam hal ini, 512), dan argumen perlindungan menunjukkan bahwa memori bersama dapat ditulis dan dibaca.

Ketika penulis anggota program berhasil dijalankan, sistem membuat dan memelihara file pendukung; di sistem saya, filenya adalah /dev/shm/shMemEx , dengan shMemEx sebagai nama saya (diberikan dalam file header shmem.h ) untuk penyimpanan bersama. Dalam versi memwriter current saat ini dan pembaca program, pernyataan:

shm_unlink(BackingFile); /* removes backing file */

menghapus file pendukung. Jika membatalkan tautan pernyataan dihilangkan, maka file pendukung tetap ada setelah program dihentikan.

pembaca , seperti penulis anggota , mengakses semaphore melalui namanya dalam panggilan ke sem_open . Tapi pembaca kemudian masuk ke status menunggu hingga memwriter menambah semaphore, yang nilai awalnya adalah 0:

if (!sem_wait(semptr)) { /* wait until semaphore != 0 */

Setelah penantian selesai, memreader membaca byte ASCII dari memori bersama, membersihkan, dan mengakhiri.

API memori bersama mencakup operasi secara eksplisit untuk menyinkronkan segmen memori bersama dan file pendukung. Operasi ini telah dihilangkan dari contoh untuk mengurangi kekacauan dan tetap fokus pada berbagi memori dan kode semaphore.

penulis anggota dan pembaca program kemungkinan besar akan dieksekusi tanpa memicu kondisi balapan meskipun kode semaphore dihapus:memwriter membuat segmen memori bersama dan segera menulisnya; pembaca bahkan tidak dapat mengakses memori bersama sampai ini dibuat. Namun, praktik terbaik mengharuskan akses memori bersama disinkronkan setiap kali tulis operasi dalam campuran, dan semaphore API cukup penting untuk disorot dalam contoh kode.

Menutup

Contoh file bersama dan memori bersama menunjukkan bagaimana proses dapat berkomunikasi melalui penyimpanan bersama , file dalam satu kasus dan segmen memori yang lain. API untuk kedua pendekatan relatif mudah. Apakah pendekatan ini memiliki kelemahan yang sama? Aplikasi modern sering berurusan dengan streaming data, memang, dengan aliran data yang sangat besar. Baik pendekatan file-bersama maupun memori-bersama tidak cocok untuk aliran data besar-besaran. Saluran dari satu jenis atau lainnya lebih cocok. Bagian 2 dengan demikian memperkenalkan saluran dan antrian pesan, sekali lagi dengan contoh kode di C.

[Unduh panduan lengkap untuk komunikasi antar-proses di Linux]


Linux
  1. Memperkenalkan panduan untuk komunikasi antar-proses di Linux

  2. Komunikasi antar-proses di Linux:Soket dan sinyal

  3. Linux – Semuanya Adalah File?

  1. Dasar-dasar Izin File Linux

  2. Rekomendasi Komunikasi Antar Proses

  3. Ubuntu Linux - Berbagi VHDX

  1. Cara memindahkan file di Linux

  2. Memahami Izin File Linux

  3. Perintah Ekor Linux