به نام خدا

Fatal Error
Welcome To Fatal Error Weblog

  سمافور ها (کمک به نوشتن برنامه خوانندگان نویسندگان و یا تولید کننده مصرف کننده)

سمافور ها در لینوکس

سمافور ها در لینوکس بر روی آرایه ای از سمافورهای عمومی اجرا می شوند و نه بر روی یک سمافور دودوئی . در نگاه اول ممکن است که این مسئله سخت به نظر بیاید ولی در مسائلی پیچیده که پردازه می خواهد چندین منبع را قفل کند ، توانایی عملیات بر روی آرابه ای از سمافور ها یک مزیت است.

توابع تعریف سمافورها عبارتند از :

#include <sys/sem.h>

int semctl(int sem_id, int sem_num, int command, ...);

int semget(key_t key, int num_sems, int sem_flags);

int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);

 

تابع semget :

این تابع یک سمافور می سازد و یا کلید یک سمافور ایجاد شده را می گیرد.

int semget(key_t key, int num_sems, int sem_flags);

پارامتر اول یک کلید است که یک عدد صحیح است به پردازه های غیر مربوط اجازه دسترسی را نمی دهد. بقبه سمافورها از مقدار برگردانده شده توسط این تابع استفاده می کنند. معمولا یک کلید سمافور مخصوص به نام IPC_PRIVATE وجود دارد که معنی آن این است که تنها پردازه ایکه آن را به وجود آورده است می تواند از آن استفاده کند. پارامتر num_sems نشان دهنده تعداد سمافور های مورد نیاز است. که معمولا مقدار آن یک است. پارامتر sem_flags مجموعه ای از پرچم هاست که خیلی شبیه به پرچم های فایل است.

تابع semop :

از این تابع برای تغییر مقدار سمافور استفاده می شود.

int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);

پارامتر اول sem_id همان مقداری است که توسط تابع semget برگردانده شده است. پارامتر sem_op یک اشاره گر به آرایه ای از ساختمان ها است که شامل اعضای زیر است :

struct sembuf

{

short sem_num;

short sem_op;

short sem_flg;

}

عضو اول تعداد سمافورها است که معمولا صفراست مگر آن که با آرایه ای از سمافورها کار می کنید. پارامتر دوم مقداری است که باید توسط سمافور عوض شود. که معمولا دو مقدار استفاده می شود یکی -1 برای اجرای عمل P و دیگری 1 برای اجرای عمل V . پارامتر آخر sem_flg معمولا SEM_UNDO می شود. این سمافور را قادر می سازد تا تغییرات سمافور را دنبال کندو اگر پردازه بدون آزاد ساختن سمافور خاتمه یابد به سیستم عامل اجازه می دهد تا به طور خودکار سمافور را آزاد سازد.

تابع  semctl :

این تابع کنترل مستقیم اطلاعات سمافور را میسر می سازد.

int semctl(int sem_id, int sem_num, int command, ...);

پارامتر اول شناسه سمافور است و پارامتر دوم شماره سمافور است و پارامتر سوم فرمان است و پارامتر آخر هم یک union semun است .

union semun

{

int val;

struct semid_ds *buf;

unsigned short *array;

}

ممکن است این ساختار در سیستم عامل شما متفاوت باشد برای اطمینان از ساختار درست این union باید header file مخصوص آن را چک کنید(sem.h)

مقادیر متفاوتی را می توان به عنوان فرمان داد که ما دو تای آنها را ذکر می کنیم :

SETVAL : برای مقدار دهی سمافور به یک مقدار معین است. مقدار مورد نظر به عنوان عضو val ساختار union فرستاده می شود. باید سمافور را برای اولین بار مقدار دهی اولیه کرد قبل از آن که از آن استفاده شود.

IPC_RMID : برای از بین بردن سمافور از آن استفاده می کنیم .

تابع semctl بنا به فرمان مقادیر متفاوتی را برمی گرداند . در این جا در صورت موفقیت مقدار صفر و در صورت شکست مقدار -1 را برمی گرداند.

برای نوشتن برنامه تولید کننده مصرف کننده می توانید از الگوی زیر استفاده کنید :

از هدر فایل های زیر استفاده کنید :

#include <sys/types.h>

#include <unistd.h>         

#include <stdio.h>

#include <sys/mman.h>

#include <sys/sem.h>

1-      ایجاد حافظه مشترک

برای ساخت حافظه مشترک می توانید از تابع زیر نیز استفاده کنید :

void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);

پارامتر اول را صفر در نظر بگیرید و چارامتر دوم نیز سایز بافر مشترک است و پارامتر سوم نوع دسترسی به آن است که می توانید آن را PORT_READ | PORT_WRITE در نظر بگیریدو پارامتر چهارم را MAP_ANONYMOUS و بعدی را MAP_SHARED و پارامتر بعدی اش را -1 و آخری را 0 بگیرید. این تابع مقداری از نوع caddr_t برمی گرداند . قطعه کد زیر از این روش استفاده کرده و بافر مشترکی می سازد :

caddr_t shared_memory;

int *buffer;

shared_memory=mmap(0, SHARED_MEM_SIZE, PROT_READ | PROT_WRITE,MAP_ANONYMOUS | MAP_SHARED, -1, 0);

 buffer = (int*) shared_memory;

2-      ایجاد سمافور های مورد نیاز

3-      در پردازه تولید کننده ، تولید کننده باید قبل از تولید و وارد شدن به ناحیه بحرانی که همان حافظه مشترک است روی سمافور wait بزند و بعد از آن سمافور را آزاد کند.

4-      در پردازه مصرف کننده نیز باید قبل از وارد شدن به ناحیه بحرانی روی سمافور wait بزند و بعد سمافور را ازاد کند.

برای نوشتن برنامه خوانندگان نویسندگان نیز باید بساه به نوع روش حلتان آن را پیاده سازی کنید.

در زیر هم برنامه shm1 یک حافظه مشترک می سازد و برنامه shm2 نیز آن حافظه مشترک را پیوست می کند و در آن می نویسد و همزمان برنامه shm1 آن را چاپ می کند. اسن برنامه در جلسه اخر حل تمرین اجرا شده است.

فابل سرآیند :

#define TEXT_SZ 2048

struct shared_use_st {

int written_by_you;

char some_text[TEXT_SZ];

};

برنامه shm1.c :

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include “shm_com.h”

int main()

{

int running = 1;

void *shared_memory = (void *)0;

struct shared_use_st *shared_stuff;

int shmid;

srand((unsigned int)getpid());

shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);

if (shmid == -1)

{

fprintf(stderr, “shmget failed\n”);

exit(EXIT_FAILURE);

}

shared_memory = shmat(shmid, (void *)0, 0);

if (shared_memory == (void *)-1)

{

fprintf(stderr, “shmat failed\n”);

exit(EXIT_FAILURE);

}

printf(“Memory attached at %X\n”, (int)shared_memory);

shared_stuff = (struct shared_use_st *)shared_memory;

shared_stuff->written_by_you = 0;

while(running)

{

if (shared_stuff->written_by_you)

{

printf(“You wrote: %s”, shared_stuff->some_text);

sleep( rand() % 4 ); /* make the other process wait for us ! */

shared_stuff->written_by_you = 0;

if (strncmp(shared_stuff->some_text, “end”, 3) == 0)

{

running = 0;

}

}

}

if (shmdt(shared_memory) == -1)

{

fprintf(stderr, “shmdt failed\n”);

exit(EXIT_FAILURE);

}

if (shmctl(shmid, IPC_RMID, 0) == -1)

{

fprintf(stderr, “shmctl(IPC_RMID) failed\n”);

exit(EXIT_FAILURE);

}

exit(EXIT_SUCCESS);

}

برنامه shm2.c :

#include <string.h>

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include “shm_com.h”

int main()

{

int running = 1;

void *shared_memory = (void *)0;

struct shared_use_st *shared_stuff;

char buffer[BUFSIZ];

int shmid;

shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);

if (shmid == -1)

{

fprintf(stderr, “shmget failed\n”);

exit(EXIT_FAILURE);

}

shared_memory = shmat(shmid, (void *)0, 0);

if (shared_memory == (void *)-1)

{

fprintf(stderr, “shmat failed\n”);

exit(EXIT_FAILURE);

}

printf(“Memory attached at %X\n”, (int)shared_memory);

shared_stuff = (struct shared_use_st *)shared_memory;

while(running)

{

while(shared_stuff->written_by_you == 1)

{

sleep(1);

printf(“waiting for client...\n”);

}

printf(“Enter some text: “);

fgets(buffer, BUFSIZ, stdin);

strncpy(shared_stuff->some_text, buffer, TEXT_SZ);

shared_stuff->written_by_you = 1;

if (strncmp(buffer, “end”, 3) == 0)

{

running = 0;

}

}

if (shmdt(shared_memory) == -1)

{

fprintf(stderr, “shmdt failed\n”);

exit(EXIT_FAILURE);

}

exit(EXIT_SUCCESS);

}

 در صورت مشکل در قسمت نظر خواهی مشکل خود را بنویسید و یا ایمیل بفرستید و در صورت لزوم با من تماس بگیرید.

اطلاعات بیشتر را می توانید از قسمت پروفایل دریافت کنید.

تگ های این مطلب :سمافور
و تگ های این مطلب :خوانندگان نویسندگان
و تگ های این مطلب :تولید کننده مصرف کننده
نویسنده : Fatal Error | ساعت ۱٢:٠٠ ‎ق.ظ روز ۱۳۸٧/۱٠/۱٢
پيام هاي ديگران () | لینک ثابت