System V

Shared Memory based on System V

หน่วยความจำที่ถูกใช้ร่วมกัน หรือเรียกว่า shared memory นั้นเป็นพื้นที่ที่จะให้โปรเซสทั้งหลายสามารถใช้เป็นที่แลกเปลี่ยนสื่อสารข้อมูลระหว่างกันได้ ซึ่ง shared memory นี้เป็นพื้นที่ของหน่วยความจำเสมือน (virtual address space) โดยแต่ละหน้า (page) ของหน่วยความจำเสมือนนี้จะถูกอ้างอิงโดยชุดเก็บตารางของแต่ละหน้า (page table) ในแต่ละตารางหน้าของโปรเซสที่กำลังใช้งานร่วมกัน ในระบบ System V การเข้าถึงพื้นที่ของหน่วยความจำที่ใช้งานร่วมกันนั้นจะถูกควบคุมไปกับชุดกุญแจและการตรวจสอบสิทธิ์การเข้าถึง (access rights)

เมื่อเกิดพื้นที่หน่วยความจำส่วนหนึ่งกลายเป็น shared memory segments ขึ้น ก็ยังไม่มีกลไกการตรวจสอบว่าจะให้แต่ละโปรเซสเข้าใช้งานอย่างไร ซึ่งจะต้องใช้กลไกอย่างอื่นช่วยเหลือแทน ตัวอย่างเช่น System V semaphores ที่ทำให้มีการทำงานที่สอดคล้องกัน เพื่อให้การเข้าถึงหน่วยความจำนี้ไม่เกิดปัญหา เป็นต้น

ฟังก์ชันและตัวแปรที่เกี่ยวข้อง

  • ไลบรารีที่เกี่ยวข้องคือ sys/ipc.h, sys/types.h และ sys/shm.h

  • ฟังก์ชัน int shmget(key_t key, size_t size, int shmflg);

    • ในการสร้างกุญแจ (key) นั้นจะมีขบวนการคล้ายกับการสร้างกุญแจของ message queues ด้วยฟังก์ชัน ftok() ถัดมาจะเป็นขนาด (size) ของส่วนของหน่วยความจำที่เข้าใช้งานร่วมกัน (shared memory segment) ในส่วนสุดท้าย (shmflg) จะเป็นการกำหนดสิทธิการเข้าถึงและแฟลกที่ระบุการสร้าง (IPC_CREAT) ซึ่งเมื่อสามารถสร้างส่วนพื้นที่หน่วยความจำนี้ได้ฟังก์ชัน shmget() จะส่งค่าหมายเลขของพื้นที่ (shmid) ออกมา

ดังตัวอย่างการกำหนดสิทธิให้เป็น 644 (rw-r--r--) ในส่วนพื้นที่ขนาด 1KB

// ...
key_t key;
int shmid;

key = ftok("/home/wiroon/somefile", 'R');
shmid = shmget(key, 1024, 0644 | IPC_CREAT);
// ...

  • ฟังก์ชัน void *shmat(int shmid, void *shmaddr, int shmflg);

    • ใช้เพื่ออ่านค่าพอยเตอร์ที่ชี้ไปยังส่วนพื้นที่สำหรับเก็บข้อมูล ซึ่งอ้างอิงจากหมายเลขพื้นที่หน่วยความจำ (shmid) ที่ได้รับจากฟังก์ชัน shmget() สำหรับส่วนของพื้นที่หน่วยจำที่จะให้ใช้นั้นก็ระบุในตัวแปร shmaddr แต่อย่างไรก็ตามควรจะกำหนดให้เป็นศูนย์ (0) เพื่อปล่อยให้ระบบปฏิบัติการเป็นคนเลือกให้ตามความเหมาะสมเอง สำหรับแฟลก (shmflg) นั้นสามารถที่จะถูกกำหนดให้เป็น SHM_RDONLY ได้ถ้าต้องการเพียงแค่อ่าน หรืออีกอย่างหนึ่งก็ตั้งให้เป็นศูนย์ (0) เพื่อใช้ทั้งอ่านและเขียน

ดังตัวอย่างการดึงตำแหน่งของพื้นที่สำหรับเก็บข้อมูลขนาด 1KB ข้างล่างนี้

// ...
key_t key;
int shmid;
char *data;

key = ftok("/home/wiroon/somefile", 'R');
shmid = shmget(key, 1024, 0644 | IPC_CREAT);
data = shmat(shmid, (void *)0, 0);
if (data == (char *)(-1))
    perror("shmat");
// ...

ดังนั้นเมื่อได้ตำแหน่งชี้พื้นที่เก็บข้อมูล ((char)*data) เรียบร้อยแล้ว ต่อไปก็เป็นเพียงการเรียกฟังก์ชันพื้นฐานสำหรับอ่านและเขียนค่าที่เป็นชนิดข้อความลงไปในพื้นที่ดังกล่าว ตัวอย่างเช่น เมื่อต้องการแสดงค่าที่อยู่ในส่วนของพื้นที่หน่วยความจำนั้น

printf("shared contents: %s\n", data);

หรือต้องการบันทึกข้อมูลลงไปในพื้นที่ส่วนนั้น

printf("Enter a string: ");
gets(data);

  • ฟังก์ชัน int shmdt(void *shmaddr);

    • ใช้เมื่อต้องการถอนออกจากการเข้าใช้พื้นที่หน่วยความจำโดยการระบุตำแหน่งของพื้นที่ของหน่วยความจำนั้น (shmaddr) ที่ได้มาจากฟังก์ชัน shmat()

สามารถใช้คำสั่ง ipcs เพื่อต้องการแสดงรายการของส่วนพื้นที่หน่วยความจำที่เปิดใช้งานร่วมกัน และสามารถใช้คำสั่ง ipcrm เพื่อลบหน่วยความจำนั้นทิ้งได้เช่นกัน

$ ipcs -m
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 294912     sriborriru 600        524288     2          dest         
0x00000000 1245185    sriborriru 600        524288     2          dest         
0x00000000 425986     sriborriru 600        524288     2          dest         
0x00000000 622595     sriborriru 600        524288     2          dest         
0x00000000 786436     sriborriru 600        524288     2          dest         
0x00000000 819205     sriborriru 600        33554432   2          dest         

ตัวอย่างที่ 1

ตัวอย่างโปรแกรมสำหรับสร้างส่วนของพื้นที่หน่วยความจำสำหรับใช้งานร่วมกัน (shared memory segments) และการเข้าใช้งานพื้นฐาน

// shmdemo.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHM_SIZE 1024  /* make it a 1K shared memory segment */

int main(int argc, char *argv[]) {
	key_t key;
	int shmid;
	char *data;

	if (argc < 2) {
		fprintf(stderr, "usage: ./shmdemo [data_to_write]\n");
		exit(1);
	}

	/* make the key: */
	if ((key = ftok("shmdemo.c", 'R')) == -1) {
		perror("ftok");
		exit(1);
	}

	/* connect to (and possibly create) the segment: */
	if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) {
		perror("shmget");
		exit(1);
	}

	/* attach to the segment to get a pointer to it: */
	data = shmat(shmid, (void*) 0, 0);
	if (data == (char*) (-1)) {
		perror("shmat");
		exit(1);
	}

	/* read or modify the segment, based on the command line: */
	if (argc == 2) {
		printf("writing to segment: \"%s\"\n", argv[1]);
		strncpy(data, argv[1], SHM_SIZE);
	} else
		printf("segment contains: \"%s\"\n", data);

	/* detach from the segment: */
	if (shmdt(data) == -1) {
		perror("shmdt");
		exit(1);
	}
	return 0;
}

ทำการคอมไพล์และรันโปรแกรม โดยใส่อาร์กิวเม้นต์เป็นชุด

$ gcc -o shmdemo shmdemo.c 
$ ./shmdemo                                                                                                                                     ─╯
usage: shmdemo [data_to_write]

$ ./shmdemo "I'm going to access this shared memory segment..."
writing to segment: "I'm going to access this shared memory segment..."

สิ่งที่ควรรู้

เนื่องจากพื้นที่หน่วยความจำส่วนนี้เป็นส่วนที่แชร์ให้แต่ละโปรเซสสามารถเข้าถึงได้ ดังนั้นอาจจะเกิดเหตุการณ์ที่มีมากกว่าหนึ่งโปรเซสต้องการเข้ามาเพื่อทำการเขียนข้อมูลลงในพื้นที่ส่วนนี้พร้อมในเวลาเดียวกัน (concurrency) ผลกระทบจากการเข้าใช้พื้นที่ในเวลาเดียวกันนี้ อาจจะทำให้เกิดการเสียหายของข้อมูลที่แต่ละโปรเซสได้เขียนลงไป แล้วส่งผลให้โปรเซสที่ต้องการจะอ่านข้อมูลจากพื้นที่นี้เพื่อนำไปประมวลผลต่อเกิดความเสียหายได้ ดังนั้นเพื่อแก้ปัญหาการเข้าใช้งานทรัพยากรที่แชร์ร่วมกันภายในระบบ จึงจำเป็นจะต้องมีกลไกการควบคุมและจัดการเหตุการณ์ที่โปรเซสจะเข้ามาพร้อมกันในเวลาเดียวกัน เช่นเทคนิค Semaphore เป็นต้น ซึ่งจะกล่าวถึงในบทถัดไป

Last updated

Assoc. Prof. Wiroon Sriborrirux, Founder of Advance Innovation Center (AIC) and Bangsaen Design House (BDH), Electrical Engineering Department, Faculty of Engineering, Burapha University