اصول عملکرد در سیستم عامل های یونیکس مانند با استفاده از لینوکس به عنوان مثال. فرآیند سبک وزن خود را ایجاد کنید
یکی از آزاردهنده ترین لحظات حرکت از محیطی به مبتنی بر ویندوزبرای استفاده خط فرمان- از دست دادن چند کار آسان. حتی در لینوکس، اگر از سیستم X Window استفاده می کنید، می توانید از ماوس خود برای کلیک کردن بر روی آن استفاده کنید برنامه جدیدو آن را باز کنید. با این حال، در خط فرمان، شما تقریباً در تکوظیفگی گیر کرده اید. در این مقاله به شما نشان خواهیم داد چگونه با استفاده از خط فرمان در لینوکس چند کار انجام دهیم.
مدیریت فرآیند پیشینه و اولویت
با این حال، هنوز راههایی برای انجام چند کار در لینوکس وجود دارد و برخی از آنها جامعتر از بقیه هستند. یک روش داخلی که نیازی به هیچ اضافی ندارد نرم افزار، به سادگی فرآیندها را در پس زمینه و در پیش زمینه جابجا می کند. ما در مورد این صحبت می کنیم. با این حال، معایبی دارد.
محافظت نشده
اولابرای ارسال یک فرآیند در پسزمینه، ابتدا باید آن را به حالت تعلیق در آورید. امکان ارسال یک برنامه از قبل در حال اجرا به پس زمینه و نگهداری همزمان آن وجود ندارد.
دوما، برای شروع یک دستور جدید باید گردش کار را شکست دهید. شما باید از کاری که در حال حاضر انجام می دهید خارج شوید و دستورات بیشتری را در پوسته تایپ کنید. کار می کند، اما ناخوشایند است.
سوم، باید خروجی های فرآیندهای پس زمینه را نظارت کنید. هر خروجی از آنها در خط فرمان ظاهر می شود و با کاری که در حال حاضر انجام می دهید تداخل خواهد داشت. بنابراین وظایف پسزمینه یا باید خروجی خود را به سمت دیگر هدایت کنند فایل جداگانه، یا باید کاملاً غیرفعال شوند.
به دلیل این کاستی ها، مشکلات بزرگی در مدیریت پس زمینه و فرآیند پیش زمینه وجود دارد. بهترین تصمیم– مطابق شکل زیر از ابزار خط فرمان “screen” استفاده کنید.
اما ابتدا - یک جلسه SSH جدید باز خواهید کرد
فراموش نکنید که شما به تازگی یک جلسه SSH جدید باز می کنید.
ممکن است همیشه باز کردن جلسات جدید ناخوشایند باشد. و این زمانی است که شما به "صفحه نمایش" نیاز دارید
سودمند صفحه نمایشبه شما امکان می دهد چندین گردش کار را به طور همزمان ایجاد کنید - نزدیکترین آنالوگ به "پنجره". به طور پیش فرض در مخازن معمولی لینوکس موجود است. با استفاده از دستور زیر آن را روی CentOS/RHEL نصب کنید:
صفحه نصب Sudo yum
باز کردن یک صفحه جدید
اکنون جلسه خود را با تایپ "screen" شروع کنید.
این ایجاد خواهد کرد پنجره خالیدر یک جلسه SSH موجود و به آن عددی بدهید که در هدر به شکل زیر نشان داده شده است:
صفحه نمایش ما در اینجا همانطور که نشان داده شده شماره "0" است. در این اسکرین شات، ما از یک دستور ساختگی “خواندن” برای مسدود کردن ترمینال و منتظر ماندن آن برای ورودی استفاده می کنیم. حالا فرض کنید می خواهیم در حالی که منتظریم کار دیگری انجام دهیم.
بازکردن صفحه نمایش جدیدو کار دیگری انجام دهیم، چاپ می کنیم:
Ctrl+a c
"ctrl+a" کلید ترکیبی پیش فرض برای کنترل صفحه نمایش در برنامه صفحه نمایش است. چیزی که بعد از آن تایپ می کنید، عمل را تعیین می کند. مثلا:
- ctrl+a c – سیصفحه جدید را فعال می کند
- ctrl+a [عدد]- به یک شماره صفحه نمایش خاص بروید
- ctrl+a k – کصفحه فعلی را خاموش می کند
- ctrl+a n - رفتن به صفحه n
- ctrl+a "- تمام صفحه های فعال در جلسه را نمایش می دهد
اگر "ctrl+a c" را فشار دهیم، صفحه جدیدی با یک عدد جدید دریافت می کنیم.
می توانید از کلیدهای مکان نما برای پیمایش در لیست و رفتن به صفحه مورد نظر استفاده کنید.
صفحهنمایشها نزدیکترین چیزی هستند که شما به پنجرهها خواهید داشت، مانند یک سیستم در یک فرمان رشته لینوکس. البته، این کار به سادگی کلیک کردن بر روی ماوس نیست، اما زیرسیستم گرافیکی آن بسیار نیازمند منابع است. با صفحه نمایش ها، می توانید تقریباً همان عملکرد را داشته باشید و چند وظیفه ای کامل را فعال کنید!
فرآیندها در یونیکس
در یونیکس ابزار اصلی سازماندهی و واحد چندوظیفه ای فرآیند است. سیستم عامل تصویر فرآیند را که نشان دهنده کد برنامه است و همچنین بخش های داده فرآیند که محیط اجرا را تعریف می کند، دستکاری می کند.
در حین اجرا یا در حین انتظار "در بال"، فرآیندها در حافظه مجازی با سازماندهی صفحه قرار می گیرند. بخشی از این حافظه مجازی به حافظه فیزیکی نگاشت شده است. بخشی از حافظه فیزیکی برای هسته سیستم عامل رزرو شده است. کاربران فقط می توانند به حافظه باقی مانده برای پردازش ها دسترسی داشته باشند. در صورت لزوم، صفحات حافظه پردازشی از حافظه فیزیکی به دیسک، به ناحیه swap مبادله می شوند. هنگام دسترسی به صفحه ای در حافظه مجازی، اگر در حافظه فیزیکی نباشد، از دیسک جابجا می شود.
حافظه مجازی توسط هسته یونیکس پیاده سازی و نگهداری می شود.
انواع فرآیند
سه نوع فرآیند در سیستم عامل یونیکس وجود دارد: سیستمیک, فرآیندهای دیمونو فرآیندهای درخواست.
فرآیندهای سیستمبخشی از هسته هستند و همیشه در آن قرار دارند حافظه دسترسی تصادفی. فرآیندهای سیستم برنامههای متناظری در قالب فایلهای اجرایی ندارند و زمانی که هسته سیستم مقداردهی اولیه میشود، به روشی خاص راهاندازی میشوند. دستورالعملها و دادههای اجرایی این فرآیندها در هسته سیستم قرار دارند، بنابراین میتوانند توابع را فراخوانی کنند و به دادههایی دسترسی پیدا کنند که سایر فرآیندها نمیتوانند به آنها دسترسی پیدا کنند.
فرآیندهای سیستم شامل فرآیند اولیه سازی اولیه، init، که مولد تمام فرآیندهای دیگر است. با اينكه initبخشی از هسته نیست و اجرای آن از یک فایل اجرایی انجام می شود، عملکرد آن برای عملکرد کل سیستم به عنوان یک کل حیاتی است.
شیاطین- اینها فرآیندهای غیر تعاملی هستند که به روش معمول راه اندازی می شوند - با بارگذاری برنامه های مربوطه خود در حافظه، و در پس زمینه اجرا می شوند. به طور معمول، دیمون ها در هنگام راه اندازی اولیه سیستم راه اندازی می شوند، اما پس از اینکه هسته اولیه شد، و عملکرد زیرسیستم های مختلف یونیکس را تضمین می کند: سیستم های دسترسی ترمینال، سیستم های چاپ، خدمات شبکهو غیره. شیاطین با هیچ کاربری مرتبط نیستند. در بیشتر مواقع، شیاطین منتظر یک فرآیند یا فرآیند دیگر برای درخواست هستند خدمات خاص.
به فرآیندهای درخواستشامل سایر فرآیندهای در حال اجرا در سیستم است. به طور معمول، اینها فرآیندهایی هستند که در یک جلسه کاربر ایجاد می شوند. مهمترین فرآیند کاربر است مفسر دستور اولیه، که اجرای دستورات کاربر را در یک سیستم یونیکس فراهم می کند.
فرآیندهای کاربر می توانند به صورت تعاملی (پیشگیرانه) و نیز اجرا شوند حالت های پس زمینه. فرآیندهای تعاملی مالکیت انحصاری ترمینال را دارند و تا زمانی که چنین فرآیندی اجرای خود را کامل نکند، کاربر به خط فرمان دسترسی ندارد.
ویژگی های فرآیند
یک فرآیند یونیکس دارای تعدادی ویژگی است که به آن اجازه می دهد سیستم عاملکار خود را مدیریت کند ویژگی های اصلی:
· شناسه فرآیند (PID)، به هسته سیستم اجازه می دهد بین فرآیندها تمایز قائل شود. هنگام ایجاد روند جدید، هسته شناسه رایگان بعدی (یعنی با هیچ فرآیندی مرتبط نیست) را به آن اختصاص می دهد. تخصیص یک شناسه معمولاً به صورت صعودی اتفاق می افتد، یعنی. شناسه فرآیند جدید بزرگتر از شناسه فرآیند ایجاد شده قبل از آن است. اگر شناسه به حداکثر مقدار (معمولاً 65737) برسد، فرآیند بعدی حداقل PID رایگان را دریافت می کند و چرخه تکرار می شود. هنگامی که یک فرآیند خارج می شود، هسته شناسه مورد استفاده خود را آزاد می کند.
· شناسه فرآیند والد (PPID)- شناسه فرآیندی که این فرآیند را ایجاد کرده است. تمام فرآیندهای موجود در سیستم به جز فرآیندهای سیستمو فرآیند init، که مولد فرآیندهای باقی مانده است، توسط یکی از فرآیندهای موجود یا قبلا موجود ایجاد می شود.
· تصحیح اولویت (NI)– اولویت نسبی فرآیند، که توسط زمانبند در هنگام تعیین سفارش راهاندازی در نظر گرفته میشود. توزیع واقعی منابع پردازنده با اولویت اجرا (ویژگی PRIبسته به عوامل متعددی، به ویژه اولویت نسبی داده شده. اولویت نسبی توسط سیستم در طول عمر فرآیند تغییر نمی کند، اگرچه می تواند توسط کاربر یا مدیر هنگام شروع فرآیند با استفاده از دستور تغییر کند. خوب. محدوده مقادیر افزایش اولویت در اکثر سیستم ها 20- تا 20 است. اگر افزایشی مشخص نشده باشد از مقدار پیش فرض 10 استفاده می شود. افزایش مثبت به معنای کاهش اولویت فعلی است. کاربران معمولی فقط می توانند یک افزایش مثبت تنظیم کنند و بنابراین، فقط اولویت را کاهش دهند. کاربر ریشهمی تواند یک افزایش منفی تعیین کند که اولویت فرآیند را افزایش می دهد و در نتیجه به بالاتر شدن آن کمک می کند کار سریع. بر خلاف اولویت نسبی، اولویت اجرای یک فرآیند به صورت پویا توسط زمانبندی تغییر می کند.
· خط پایانه (TTY)- یک پایانه یا شبه پایانه مرتبط با یک فرآیند. این ترمینال با استاندارد مرتبط است جریان ها: ورودی, مرخصی روزانهو جریان پیامدر مورد خطاها جریان ها ( کانال های برنامه) هستند به معنی استانداردارتباطات بین فرآیندی در سیستم عامل یونیکس فرآیندهای دیمون با یک ترمینال مرتبط نیستند.
· شناسه های کاربر واقعی (UID) و موثر (EUID).. شناسه کاربری واقعی یک فرآیند معین، شناسه کاربری است که فرآیند را آغاز کرده است. شناسه موثر برای تعیین حقوق دسترسی فرآیند به منابع سیستم (در درجه اول منابع) استفاده می شود فایل سیستم). معمولاً شناسههای واقعی و مؤثر یکسان هستند، یعنی. این فرآیند در سیستم دارای حقوقی مشابه با کاربری است که آن را راه اندازی کرده است. با این حال، می توان با تنظیم به یک فرآیند حقوق بیشتری نسبت به کاربر داد بیت SUIDزمانی که شناسه موثر روی شناسه صاحب فایل اجرایی تنظیم شود (مثلاً کاربر ریشه).
· شناسه های گروه واقعی (GID) و موثر (EGID).شناسه گروه واقعی برابر با شناسه گروه اصلی یا فعلی کاربری است که فرآیند را آغاز کرده است. شناسه موثر برای تعیین حقوق دسترسی به منابع سیستم از طرف یک گروه استفاده می شود. معمولاً شناسه گروه مؤثر همان شناسه واقعی است. اما اگر فایل اجرایی روی بیت SGID، چنین فایلی با شناسه گروه مالک موثر اجرا می شود.
کار آزمایشگاهی شماره 3
برنامه نویسی چند وظیفه ای درلینوکس
1. هدف کار:با کامپایلر gcc، تکنیک های اشکال زدایی برنامه و توابع کار با فرآیندها آشنا شوید.
2. اطلاعات نظری مختصر
حداقل مجموعه سوئیچ های کامپایلر gcc عبارتند از - Wall (نمایش همه خطاها و هشدارها) و - o (فایل خروجی):
gcc - دیوار - o print_pid print_pid. ج
تیم ایجاد خواهد کرد فایل اجرایی print_pid.
کتابخانه استاندارد C (libc، پیاده سازی شده در لینوکس در glibc) از قابلیت های چندوظیفه ای Unix System V (از این پس SysV) بهره می برد. در libc، نوع pid_t به عنوان یک عدد صحیح که می تواند حاوی یک pid باشد، تعریف می شود. تابعی که pid فرآیند جاری را گزارش میکند، یک نمونه اولیه از pid_t getpid(void) دارد و همراه با pid_t در unistd تعریف میشود. h و sys/types. h).
برای ایجاد یک فرآیند جدید، از تابع فورک استفاده کنید:
چنگال pid_t (باطل)
با درج تاخیر طول تصادفی با استفاده از توابع خواب و رند، میتوانید تأثیر چندوظیفهای را واضحتر ببینید:
این باعث می شود که برنامه به مدت چند ثانیه تصادفی "خواب" شود: از 0 تا 3.
برای فراخوانی یک تابع به عنوان فرآیند فرزند، کافیست آن را پس از شاخهبندی فراخوانی کنید:
// اگر یک پردازش فرزند در حال اجرا است، تابع را فراخوانی کنید
pid=process(arg);
// از فرآیند خارج شوید
اغلب لازم است یک برنامه دیگر به عنوان فرآیند فرزند اجرا شود. برای این کار از توابع خانواده exec استفاده کنید:
// اگر یک پردازش فرزند در حال اجرا است، برنامه را فراخوانی کنید
if (execl(."/file","file",arg, NULL)<0) {
printf("خطا هنگام شروع فرآیند\n");
else printf("فرآیند شروع شد (pid=%d)\n", pid);
// از فرآیند خارج شوید
اغلب، یک فرآیند والدین برای انجام عملیات در زمان مناسب نیاز به تبادل اطلاعات با فرزندان خود یا حداقل همگام سازی با آنها دارد. یکی از راههای همگامسازی فرآیندها، توابع انتظار و انتظار است:
#عبارتند از
#عبارتند از
pid_t wait(int *status) - اجرای فرآیند فعلی را تا زمانی که هر یک از پردازش های فرزند آن خاتمه یابد به حالت تعلیق در می آورد.
pid_t waitpid (pid_t pid، int *وضعیت، گزینههای int) - اجرای فرآیند جاری را تا زمانی که فرآیند مشخص شده تکمیل شود یا اتمام فرآیند مشخص شده را بررسی کند، به حالت تعلیق در میآید.
اگر میخواهید وضعیت پردازش فرزند را هنگام پایان یافتن و مقداری که برمیگرداند، بیابید، از ماکرو WEXITSTATUS استفاده کنید و وضعیت پردازش فرزند را به عنوان پارامتر به آن ارسال کنید.
status=waitpid(pid,&status, WNOHANG);
اگر (pid == وضعیت) (
printf("PID: %d، نتیجه = %d\n"، pid، WEXITSTATUS(وضعیت)); )
برای تغییر اولویت های فرآیندهای تخم ریزی شده، از اولویت و توابع استفاده می شود. اولویت ها در محدوده 20- (بالاترین) تا 20 (پایین ترین) تنظیم می شوند، مقدار عادی 0 است. توجه داشته باشید که فقط یک ابرکاربر می تواند اولویت را بالاتر از حد معمول افزایش دهد!
#عبارتند از
#عبارتند از
فرآیند int (int i) (
اولویت (PRIO_PROCESS, getpid(),i);
printf("Process %d ThreadID: %d کار با اولویت %d\n",i, getpid(),getpriority(PRIO_PROCESS, getpid()));
return(getpriority(PRIO_PROCESS, getpid()));
برای از بین بردن یک فرآیند، از تابع kill استفاده کنید:
#عبارتند از
#عبارتند از
int kill(pid_t pid, int sig);
اگر pid > 0 باشد، PID فرآیندی که سیگنال به آن ارسال می شود را مشخص می کند. اگر pid = 0 باشد، سیگنال به تمام فرآیندهای گروهی که فرآیند جاری به آن تعلق دارد ارسال می شود.
sig - نوع سیگنال برخی از انواع سیگنال در لینوکس:
SIGKILL این سیگنال باعث می شود که فرآیند بلافاصله خاتمه یابد. فرآیند نمی تواند این سیگنال را نادیده بگیرد.
SIGTERM این سیگنال درخواستی برای پایان دادن به فرآیند است.
SIGCHLD هنگامی که یکی از پردازش های فرزندش خاتمه می یابد، سیستم این سیگنال را به یک فرآیند ارسال می کند. مثال:
اگر (pid[i] == وضعیت) (
printf("ThreadID: %d با وضعیت %d\n به پایان رسید"، pid[i]، WEXITSTATUS(وضعیت));
else kill(pid[i],SIGKILL);
3. دستورالعمل های روشی
3.1. برای آشنایی با گزینه های کامپایلر gcc و توضیحات توابع زبان C، از دستورالعمل man and info استفاده کنید.
3.2. برای اشکال زدایی برنامه ها استفاده از ویرایشگر داخلی مدیر فایل راحت است فرمانده نیمه شب(MC)، که ساختارهای مختلف زبان را با رنگ برجسته می کند و موقعیت مکان نما را در فایل (ردیف، ستون) در خط بالای صفحه نشان می دهد.
3.3. مدیر فایل Midnight Commander دارای یک بافر فرمان است که می توان آن را با یک میانبر صفحه کلید فراخوانی کرد
3.4. به یاد داشته باشید که دایرکتوری فعلی در مسیر موجود نیست، بنابراین باید برنامه را به صورت "./print_pid" از خط فرمان اجرا کنید. در MC، فقط ماوس را روی فایل ببرید و کلیک کنید
3.5. برای مشاهده نتیجه اجرای برنامه از میانبر صفحه کلید استفاده کنید
3.6. برای ثبت نتایج اجرای برنامه، توصیه می شود از تغییر مسیر خروجی از کنسول به یک فایل استفاده کنید: ./test > result. txt
3.7. برای دسترسی به فایل های ایجاد شده در سرور لینوکس، از پروتکل ftp استفاده کنید، برنامه کلاینت برای آن در ویندوز 2000 موجود است و در آن تعبیه شده است. مدیر فایلدور. که در آن حسابو رمز عبور همان است که هنگام اتصال از طریق ssh است.
4.1. با گزینه ها و روش های کامپایلر gcc برای اشکال زدایی برنامه ها آشنا شوید.
4.2. برای انواع وظایف از کار آزمایشگاهی شماره 1، برنامه ای را بنویسید و اشکال زدایی کنید که فرآیند تولید شده را پیاده سازی کند.
4.3. برای گزینه های کار از کار آزمایشگاهیشماره 1 برنامه ای را می نویسد و اشکال زدایی می کند که یک فرآیند والد را اجرا می کند که وضعیت فرآیندهای فرزند - برنامه ها را فراخوانی و نظارت می کند (منتظر تکمیل یا از بین بردن آنها، بسته به گزینه).
4.4. برای انواع وظایف از کار آزمایشگاهی شماره 1، برنامه ای را بنویسید و اشکال زدایی کنید که یک فرآیند والد را اجرا می کند که وضعیت فرآیندهای فرزند - توابع را فراخوانی و نظارت می کند (بسته به نوع، در انتظار تکمیل یا از بین بردن آنها هستند).
5. گزینه هایی برای وظایفگزینه های مربوط به کارهای آزمایشگاهی شماره 1 را ببینید
6. محتویات گزارش.
6.1. هدف کار.
6.2. گزینه وظیفه.
6.3. لیست برنامه ها
6.4. پروتکل های اجرای برنامه
7. کنترل سوالات
7.1. ویژگی های کامپایل و اجرای برنامه های C در لینوکس.
7.2. pid چیست، چگونه آن را در سیستم عامل و برنامه تعیین کنیم؟
7.3. تابع فورک - هدف، کاربرد، مقدار بازگشتی.
7.4. چگونه یک تابع را در یک فرآیند تخم ریزی شده اجرا کنیم؟ برنامه؟
7.5. راه هایی برای همگام سازی فرآیندهای والدین و فرزند
7.6. چگونه می توان از وضعیت فرآیند تخم ریزی شده در هنگام پایان یافتن و مقدار بازگشتی آن مطلع شد؟
7.7. چگونه اولویت های فرآیند را مدیریت کنیم؟
7.8. چگونه یک فرآیند را در سیستم عامل و برنامه از بین ببریم؟
موضوع چند رشته ای را در هسته لینوکس ادامه می دهیم. آخرین باری که در مورد وقفه ها، پردازش آنها و تسکلت ها صحبت کردم، و از آنجایی که در ابتدا قرار بود این یک مقاله باشد، در داستان خود در مورد صف کار به تسکلت ها اشاره می کنم، با این فرض که خواننده از قبل با آنها آشنا است.
مانند دفعه قبل، سعی خواهم کرد تا جایی که ممکن است داستانم را با جزئیات و جزییات ارائه کنم.
مقالات این مجموعه:
- چند وظیفه ای در هسته لینوکس: صف کاری
صف کار
صف کار- این ها موجودیت های پیچیده تر و سنگین تری نسبت به tasklet ها هستند. من حتی سعی نمی کنم تمام پیچیدگی های پیاده سازی را در اینجا شرح دهم، اما امیدوارم مهمترین چیزها را با جزئیات بیشتر یا کمتر تجزیه و تحلیل کنم.صفهای کاری، مانند taskletها، برای پردازش وقفههای معوق به کار میروند (اگرچه میتوان از آنها برای مقاصد دیگر استفاده کرد)، اما برخلاف تسکلتها، در چارچوب یک فرآیند هسته اجرا میشوند؛ بر این اساس، لازم نیست اتمی باشند و میتوانند از خواب استفاده کنند. () عملکرد، ابزارهای مختلف همگام سازی و غیره.
بیایید ابتدا بفهمیم که فرآیند پردازش صف کار به طور کلی چگونه سازماندهی می شود. تصویر آن را بسیار تقریبی و ساده نشان می دهد، چگونگی اتفاق افتادن همه چیز در زیر به تفصیل شرح داده شده است.
چندین نهاد درگیر این ماده تاریک هستند.
اولا، مورد کار(فقط به طور خلاصه کار کنید) ساختاری است که عملکردی را توصیف می کند (مثلاً یک کنترل کننده وقفه) که می خواهیم برنامه ریزی کنیم. می توان آن را به عنوان آنالوگ ساختار tasklet در نظر گرفت. هنگام برنامه ریزی، Tasklet ها به صف های پنهان از کاربر اضافه می شدند، اما اکنون باید از یک صف خاص استفاده کنیم - صف کار.
Tasklet ها توسط تابع زمانبند رها می شوند و صف کاری توسط رشته های خاصی به نام کارگران پردازش می شود.
کارگر'ها اجرای ناهمزمان کارها را از صف کار ارائه می دهند. اگرچه آنها کار را به ترتیب چرخش می نامند، اما در حالت کلی بحثی از اجرای سختگیرانه و متوالی وجود ندارد: از این گذشته، پیش گرفتن، خواب، انتظار و غیره در اینجا اتفاق می افتد.
به طور کلی، کارگران رشته های هسته هستند، یعنی توسط زمانبندی هسته اصلی لینوکس کنترل می شوند. اما کارگران تا حدی در برنامه ریزی برای سازماندهی اضافی اجرای موازی کار دخالت می کنند. در ادامه به تفصیل بیشتر به این موضوع پرداخته خواهد شد.
برای تشریح قابلیتهای اصلی مکانیسم صف کاری، پیشنهاد میکنم API را بررسی کنید.
درباره صف و ایجاد آن
alloc_workqueue (fmt، flags، max_active، args...)پارامترهای fmt و args فرمت printf برای نام و آرگومان های آن هستند. پارامتر max_activate مسئول حداکثر تعداد کارهایی است که از این صف می توان به صورت موازی روی یک CPU اجرا کرد.
یک صف را می توان با پرچم های زیر ایجاد کرد:
- WQ_HIGHPRI
- WQ_UNBOUND
- WQ_CPU_INTENSIVE
- WQ_FREEZABLE
- WQ_MEM_RECLAIM
در صف های مرتبطوقتی اضافه میشود، کارها به CPU فعلی متصل میشوند، یعنی در چنین صفهایی، کارها روی هستهای که آن را زمانبندی میکند، اجرا میشوند. در این راستا، صف های محدود شده شبیه به tasklet ها هستند.
در صف های غیر متصلکارها را می توان روی هر هسته ای اجرا کرد.
یکی از ویژگی های مهم اجرای صف کار در هسته لینوکس، سازماندهی اضافی اجرای موازی است که در صف های محدود وجود دارد. در زیر با جزئیات بیشتر نوشته شده است، اما اکنون می گویم که به گونه ای انجام می شود که تا حد امکان از حافظه کمتری استفاده می شود و پردازنده بیکار نمی ماند. همه اینها با این فرض اجرا می شود که یک کار از چرخه های پردازنده زیادی استفاده نمی کند.
این مورد برای صف های غیر متصل نیست. اساساً، چنین صف هایی به سادگی زمینه را برای کارگران فراهم می کنند و آنها را در اسرع وقت شروع می کنند.
بنابراین، در صورتی که انتظار می رود حجم کاری فشرده CPU وجود داشته باشد، باید از صف های متصل استفاده شود، زیرا در این حالت زمان بندی اجرای موازی روی چندین هسته را انجام می دهد.
بر اساس قیاس با مجموعههای وظیفه، میتوان به کارها اولویت اجرا، معمولی یا زیاد اختصاص داد. اولویت برای کل صف مشترک است. به طور پیش فرض، صف دارای اولویت عادی است و اگر پرچم را تنظیم کنید WQ_HIGHPRI، سپس، بر این اساس، بالا.
پرچم WQ_CPU_INTENSIVEفقط برای صف های محدود منطقی است. این پرچم امتناع از شرکت در یک سازمان اضافی اعدام موازی است. این پرچم باید زمانی استفاده شود که انتظار می رود کار زمان زیادی از CPU را مصرف کند، در این صورت بهتر است مسئولیت به زمانبند منتقل شود. این با جزئیات بیشتر در زیر توضیح داده شده است.
پرچم ها WQ_FREEZABLEو WQ_MEM_RECLAIMخاص و خارج از محدوده موضوع هستند، بنابراین ما در مورد آنها به تفصیل نمی پردازیم.
گاهی اوقات منطقی است که صف های خود را ایجاد نکنید، بلکه از صف های رایج استفاده کنید. اصلی ترین ها:
- system_wq - صف محدود برای کار سریع
- system_long_wq - یک صف محدود برای کارهایی که انتظار می رود اجرای آنها زمان زیادی ببرد
- system_unbound_wq - صف بدون محدودیت
در مورد کار و برنامه ریزی آنها
حال به آثار می پردازیم. ابتدا، اجازه دهید به ماکروهای اولیه سازی، اعلان و آماده سازی نگاه کنیم:DECLARE(_DELAYED)_WORK(name, void (*function)(structwork_struct *work)); /* در زمان کامپایل */ INIT(_DELAYED)_WORK(_work, _func); /* در حین اجرا */ PREPARE(_DELAYED)_WORK(_work, _func); /* برای تغییر تابع در حال اجرا */
کارها با استفاده از توابع به صف اضافه می شوند:
bool queue_work(struct workqueue_struct *wq, struct work_struct *work); bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay); /* کار فقط پس از اتمام تاخیر به صف اضافه می شود */
این ارزش دارد که با جزئیات بیشتر در مورد آن صحبت کنیم. اگرچه ما یک صف را به عنوان یک پارامتر مشخص میکنیم، در واقع، workها آنطور که به نظر میرسد در خود صف کار قرار نمیگیرند، بلکه در یک موجودیت کاملاً متفاوت - در لیست صف ساختار worker_pool قرار میگیرند. ساختار کارگر_استخردر واقع مهمترین موجود در سازماندهی مکانیزم صف کار است، اگرچه برای کاربر در پشت صحنه باقی می ماند. کارگران با آنها کار می کنند و تمام اطلاعات اولیه در آنها وجود دارد.
حال بیایید ببینیم چه استخرهایی در سیستم وجود دارد.
برای شروع، استخرهایی برای صف های محدود شده (در تصویر). برای هر CPU، دو استخر کارگر به صورت ایستا اختصاص داده شده است: یکی برای کارهای با اولویت بالا، دیگری برای کارهای با اولویت معمولی. یعنی اگر چهار هسته داشته باشیم، با وجود اینکه به تعداد دلخواه صف کاری وجود دارد، تنها هشت استخر محدود وجود خواهد داشت.
وقتی یک صف کاری ایجاد می کنیم، برای هر CPU یک سرویس اختصاص داده شده است استخر_صف کار(pwq). هر یک از این دسته pool_workqueue با یک Worker Pool مرتبط است که بر روی همان CPU تخصیص داده شده است و از نظر اولویت با نوع صف مطابقت دارد. از طریق آنها، صف کار با استخر کارگر در تعامل است.
کارگران بدون اینکه تشخیص دهند که در اصل به کدام صف کار تعلق داشته اند، کار را از استخر کارگران بی رویه اجرا می کنند.
برای صف های غیر متصل، استخرهای کارگر به صورت پویا تخصیص داده می شوند. تمام صف ها را می توان با توجه به پارامترهایشان به کلاس های هم ارزی تقسیم کرد و برای هر یک از این دسته ها یک گروه کارگر مخصوص به خود ایجاد می شود. آنها با استفاده از یک جدول هش ویژه قابل دسترسی هستند، که در آن کلید مجموعه ای از پارامترها است، و مقدار، به ترتیب، استخر کارگر است.
در واقع، برای صفهای محدود همه چیز کمی پیچیدهتر است: اگر برای صفهای محدود pwq و صفها برای هر CPU ایجاد میشوند، در اینجا آنها برای هر گره NUMA ایجاد میشوند، اما این یک بهینهسازی اضافی است که ما جزئیات آن را بررسی نمیکنیم.
انواع چیزهای کوچک
من همچنین چند عملکرد از API برای تکمیل تصویر ارائه خواهم کرد، اما در مورد آنها با جزئیات صحبت نمی کنم:/* تکمیل اجباری */ bool flush_work(struct work_struct *work); bool flush_delayed_work(struct delayed_work *dwork); /* لغو اجرای کار */ bool cancel_work_sync(struct work_struct *work); bool cancel_delayed_work(struct delayed_work *dwork); bool cancel_delayed_work_sync(struct delayed_work *dwork); /* حذف یک صف */ void destroy_workqueue(struct workqueue_struct *wq);
کارگران چگونه کار خود را انجام می دهند
اکنون که با API آشنا شدیم، بیایید سعی کنیم با جزئیات بیشتر نحوه عملکرد و مدیریت آن را درک کنیم.هر استخر دارای مجموعه ای از کارگران است که وظایف را انجام می دهند. علاوه بر این، تعداد کارگران به طور پویا تغییر می کند و با شرایط فعلی سازگار می شود.
همانطور که قبلا متوجه شدیم، کارگران رشته هایی هستند که کار را در زمینه هسته انجام می دهند. کارگر آنها را به ترتیب، یکی پس از دیگری، از استخر کارگر مرتبط با خود بازیابی می کند، و کارگران، همانطور که قبلاً می دانیم، می توانند به صف های منبع مختلف تعلق داشته باشند.
کارگران به طور مشروط می توانند در سه حالت منطقی باشند: آنها می توانند بیکار، در حال اجرا یا مدیریت باشند.
کارگر می تواند بیکار بایستو هیچ کاری نکن به عنوان مثال، این زمانی است که همه کارها قبلاً در حال اجرا هستند. وقتی یک کارگر وارد این حالت می شود، به خواب می رود و بر این اساس، تا زمانی که از خواب بیدار نشود، اجرا نمی شود.
اگر مدیریت استخر مورد نیاز نباشد و لیست کارهای برنامه ریزی شده خالی نباشد، کارگر شروع به اجرای آنها می کند. ما به طور متعارف چنین کارگرانی را می نامیم در حال اجرا.
در صورت لزوم، کارگر نقش را بر عهده می گیرد مدیراستخر. یک استخر می تواند فقط یک کارگر مدیر داشته باشد یا اصلاً کارگر نداشته باشد. وظیفه آن حفظ تعداد بهینه کارگران در هر استخر است. او چگونه این کار را انجام می دهد؟ اولاً کارگرانی که برای مدت طولانی بیکار بوده اند حذف می شوند. ثانیاً، اگر سه شرط به طور همزمان برآورده شود، کارگران جدید ایجاد می شوند:
- هنوز کارهایی برای تکمیل وجود دارد (کارها در استخر)
- بدون کارگر بیکار
- هیچ کارگر شاغلی وجود ندارد (یعنی فعال و بدون خواب)
حسابداری کارگران شاغل مستقیماً از زمانبندی هسته اصلی لینوکس انجام میشود. این مکانیسم کنترلی سطح همزمانی بهینه را تضمین میکند، از ایجاد تعداد زیادی کارگر در صف کار جلوگیری میکند، اما باعث نمیشود که کار برای مدت طولانی بیمورد منتظر بماند.
علاقه مندان می توانند به تابع worker در هسته نگاه کنند که به آن worker_thread() می گویند.
تمام توابع و ساختارهای توصیف شده را می توان با جزئیات بیشتر در فایل ها یافت include/linux/workqueue.h, هسته/صف کار.cو kernel/workqueue_internal.h. همچنین مستنداتی در مورد صف کار در وجود دارد Documentation/workqueue.txt.
همچنین شایان ذکر است که مکانیسم صف کاری در هسته نه تنها برای پردازش وقفه های معوق استفاده می شود (اگرچه این یک سناریوی نسبتاً رایج است).
بنابراین، ما به مکانیسمهای مدیریت وقفههای معوق در هسته لینوکس - tasklet و workqueue که شکل خاصی از چندوظیفگی هستند، نگاه کردیم. میتوانید در مورد وقفهها، تسکلتها و صفهای کاری در کتاب «درایورهای دستگاه لینوکس» نوشته جاناتان کوربت، گرگ کروآ-هارتمن، الساندرو روبینی، اطلاعاتی که در آنجا وجود دارد گاهی قدیمی است.
موضوع چند رشته ای را در هسته لینوکس ادامه می دهیم. آخرین باری که در مورد وقفه ها، پردازش آنها و تسکلت ها صحبت کردم، و از آنجایی که در ابتدا قرار بود این یک مقاله باشد، در داستان خود در مورد صف کار به تسکلت ها اشاره می کنم، با این فرض که خواننده از قبل با آنها آشنا است.
مانند دفعه قبل، سعی خواهم کرد تا جایی که ممکن است داستانم را با جزئیات و جزییات ارائه کنم.
مقالات این مجموعه:
- چند وظیفه ای در هسته لینوکس: صف کاری
صف کار
صف کار- این ها موجودیت های پیچیده تر و سنگین تری نسبت به tasklet ها هستند. من حتی سعی نمی کنم تمام پیچیدگی های پیاده سازی را در اینجا شرح دهم، اما امیدوارم مهمترین چیزها را با جزئیات بیشتر یا کمتر تجزیه و تحلیل کنم.صفهای کاری، مانند taskletها، برای پردازش وقفههای معوق به کار میروند (اگرچه میتوان از آنها برای مقاصد دیگر استفاده کرد)، اما برخلاف تسکلتها، در چارچوب یک فرآیند هسته اجرا میشوند؛ بر این اساس، لازم نیست اتمی باشند و میتوانند از خواب استفاده کنند. () عملکرد، ابزارهای مختلف همگام سازی و غیره.
بیایید ابتدا بفهمیم که فرآیند پردازش صف کار به طور کلی چگونه سازماندهی می شود. تصویر آن را بسیار تقریبی و ساده نشان می دهد، چگونگی اتفاق افتادن همه چیز در زیر به تفصیل شرح داده شده است.
چندین نهاد درگیر این ماده تاریک هستند.
اولا، مورد کار(فقط به طور خلاصه کار کنید) ساختاری است که عملکردی را توصیف می کند (مثلاً یک کنترل کننده وقفه) که می خواهیم برنامه ریزی کنیم. می توان آن را به عنوان آنالوگ ساختار tasklet در نظر گرفت. هنگام برنامه ریزی، Tasklet ها به صف های پنهان از کاربر اضافه می شدند، اما اکنون باید از یک صف خاص استفاده کنیم - صف کار.
Tasklet ها توسط تابع زمانبند رها می شوند و صف کاری توسط رشته های خاصی به نام کارگران پردازش می شود.
کارگر'ها اجرای ناهمزمان کارها را از صف کار ارائه می دهند. اگرچه آنها کار را به ترتیب چرخش می نامند، اما در حالت کلی بحثی از اجرای سختگیرانه و متوالی وجود ندارد: از این گذشته، پیش گرفتن، خواب، انتظار و غیره در اینجا اتفاق می افتد.
به طور کلی، کارگران رشته های هسته هستند، یعنی توسط زمانبندی هسته اصلی لینوکس کنترل می شوند. اما کارگران تا حدی در برنامه ریزی برای سازماندهی اضافی اجرای موازی کار دخالت می کنند. در ادامه به تفصیل بیشتر به این موضوع پرداخته خواهد شد.
برای تشریح قابلیتهای اصلی مکانیسم صف کاری، پیشنهاد میکنم API را بررسی کنید.
درباره صف و ایجاد آن
alloc_workqueue (fmt، flags، max_active، args...)پارامترهای fmt و args فرمت printf برای نام و آرگومان های آن هستند. پارامتر max_activate مسئول حداکثر تعداد کارهایی است که از این صف می توان به صورت موازی روی یک CPU اجرا کرد.
یک صف را می توان با پرچم های زیر ایجاد کرد:
- WQ_HIGHPRI
- WQ_UNBOUND
- WQ_CPU_INTENSIVE
- WQ_FREEZABLE
- WQ_MEM_RECLAIM
در صف های مرتبطوقتی اضافه میشود، کارها به CPU فعلی متصل میشوند، یعنی در چنین صفهایی، کارها روی هستهای که آن را زمانبندی میکند، اجرا میشوند. در این راستا، صف های محدود شده شبیه به tasklet ها هستند.
در صف های غیر متصلکارها را می توان روی هر هسته ای اجرا کرد.
یکی از ویژگی های مهم اجرای صف کار در هسته لینوکس، سازماندهی اضافی اجرای موازی است که در صف های محدود وجود دارد. در زیر با جزئیات بیشتر نوشته شده است، اما اکنون می گویم که به گونه ای انجام می شود که تا حد امکان از حافظه کمتری استفاده می شود و پردازنده بیکار نمی ماند. همه اینها با این فرض اجرا می شود که یک کار از چرخه های پردازنده زیادی استفاده نمی کند.
این مورد برای صف های غیر متصل نیست. اساساً، چنین صف هایی به سادگی زمینه را برای کارگران فراهم می کنند و آنها را در اسرع وقت شروع می کنند.
بنابراین، در صورتی که انتظار می رود حجم کاری فشرده CPU وجود داشته باشد، باید از صف های متصل استفاده شود، زیرا در این حالت زمان بندی اجرای موازی روی چندین هسته را انجام می دهد.
بر اساس قیاس با مجموعههای وظیفه، میتوان به کارها اولویت اجرا، معمولی یا زیاد اختصاص داد. اولویت برای کل صف مشترک است. به طور پیش فرض، صف دارای اولویت عادی است و اگر پرچم را تنظیم کنید WQ_HIGHPRI، سپس، بر این اساس، بالا.
پرچم WQ_CPU_INTENSIVEفقط برای صف های محدود منطقی است. این پرچم امتناع از شرکت در یک سازمان اضافی اعدام موازی است. این پرچم باید زمانی استفاده شود که انتظار می رود کار زمان زیادی از CPU را مصرف کند، در این صورت بهتر است مسئولیت به زمانبند منتقل شود. این با جزئیات بیشتر در زیر توضیح داده شده است.
پرچم ها WQ_FREEZABLEو WQ_MEM_RECLAIMخاص و خارج از محدوده موضوع هستند، بنابراین ما در مورد آنها به تفصیل نمی پردازیم.
گاهی اوقات منطقی است که صف های خود را ایجاد نکنید، بلکه از صف های رایج استفاده کنید. اصلی ترین ها:
- system_wq - صف محدود برای کار سریع
- system_long_wq - یک صف محدود برای کارهایی که انتظار می رود اجرای آنها زمان زیادی ببرد
- system_unbound_wq - صف بدون محدودیت
در مورد کار و برنامه ریزی آنها
حال به آثار می پردازیم. ابتدا، اجازه دهید به ماکروهای اولیه سازی، اعلان و آماده سازی نگاه کنیم:DECLARE(_DELAYED)_WORK(name, void (*function)(structwork_struct *work)); /* در زمان کامپایل */ INIT(_DELAYED)_WORK(_work, _func); /* در حین اجرا */ PREPARE(_DELAYED)_WORK(_work, _func); /* برای تغییر تابع در حال اجرا */
کارها با استفاده از توابع به صف اضافه می شوند:
bool queue_work(struct workqueue_struct *wq, struct work_struct *work); bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay); /* کار فقط پس از اتمام تاخیر به صف اضافه می شود */
این ارزش دارد که با جزئیات بیشتر در مورد آن صحبت کنیم. اگرچه ما یک صف را به عنوان یک پارامتر مشخص میکنیم، در واقع، workها آنطور که به نظر میرسد در خود صف کار قرار نمیگیرند، بلکه در یک موجودیت کاملاً متفاوت - در لیست صف ساختار worker_pool قرار میگیرند. ساختار کارگر_استخردر واقع مهمترین موجود در سازماندهی مکانیزم صف کار است، اگرچه برای کاربر در پشت صحنه باقی می ماند. کارگران با آنها کار می کنند و تمام اطلاعات اولیه در آنها وجود دارد.
حال بیایید ببینیم چه استخرهایی در سیستم وجود دارد.
برای شروع، استخرهایی برای صف های محدود شده (در تصویر). برای هر CPU، دو استخر کارگر به صورت ایستا اختصاص داده شده است: یکی برای کارهای با اولویت بالا، دیگری برای کارهای با اولویت معمولی. یعنی اگر چهار هسته داشته باشیم، با وجود اینکه به تعداد دلخواه صف کاری وجود دارد، تنها هشت استخر محدود وجود خواهد داشت.
وقتی یک صف کاری ایجاد می کنیم، برای هر CPU یک سرویس اختصاص داده شده است استخر_صف کار(pwq). هر یک از این دسته pool_workqueue با یک Worker Pool مرتبط است که بر روی همان CPU تخصیص داده شده است و از نظر اولویت با نوع صف مطابقت دارد. از طریق آنها، صف کار با استخر کارگر در تعامل است.
کارگران بدون اینکه تشخیص دهند که در اصل به کدام صف کار تعلق داشته اند، کار را از استخر کارگران بی رویه اجرا می کنند.
برای صف های غیر متصل، استخرهای کارگر به صورت پویا تخصیص داده می شوند. تمام صف ها را می توان با توجه به پارامترهایشان به کلاس های هم ارزی تقسیم کرد و برای هر یک از این دسته ها یک گروه کارگر مخصوص به خود ایجاد می شود. آنها با استفاده از یک جدول هش ویژه قابل دسترسی هستند، که در آن کلید مجموعه ای از پارامترها است، و مقدار، به ترتیب، استخر کارگر است.
در واقع، برای صفهای محدود همه چیز کمی پیچیدهتر است: اگر برای صفهای محدود pwq و صفها برای هر CPU ایجاد میشوند، در اینجا آنها برای هر گره NUMA ایجاد میشوند، اما این یک بهینهسازی اضافی است که ما جزئیات آن را بررسی نمیکنیم.
انواع چیزهای کوچک
من همچنین چند عملکرد از API برای تکمیل تصویر ارائه خواهم کرد، اما در مورد آنها با جزئیات صحبت نمی کنم:/* تکمیل اجباری */ bool flush_work(struct work_struct *work); bool flush_delayed_work(struct delayed_work *dwork); /* لغو اجرای کار */ bool cancel_work_sync(struct work_struct *work); bool cancel_delayed_work(struct delayed_work *dwork); bool cancel_delayed_work_sync(struct delayed_work *dwork); /* حذف یک صف */ void destroy_workqueue(struct workqueue_struct *wq);
کارگران چگونه کار خود را انجام می دهند
اکنون که با API آشنا شدیم، بیایید سعی کنیم با جزئیات بیشتر نحوه عملکرد و مدیریت آن را درک کنیم.هر استخر دارای مجموعه ای از کارگران است که وظایف را انجام می دهند. علاوه بر این، تعداد کارگران به طور پویا تغییر می کند و با شرایط فعلی سازگار می شود.
همانطور که قبلا متوجه شدیم، کارگران رشته هایی هستند که کار را در زمینه هسته انجام می دهند. کارگر آنها را به ترتیب، یکی پس از دیگری، از استخر کارگر مرتبط با خود بازیابی می کند، و کارگران، همانطور که قبلاً می دانیم، می توانند به صف های منبع مختلف تعلق داشته باشند.
کارگران به طور مشروط می توانند در سه حالت منطقی باشند: آنها می توانند بیکار، در حال اجرا یا مدیریت باشند.
کارگر می تواند بیکار بایستو هیچ کاری نکن به عنوان مثال، این زمانی است که همه کارها قبلاً در حال اجرا هستند. وقتی یک کارگر وارد این حالت می شود، به خواب می رود و بر این اساس، تا زمانی که از خواب بیدار نشود، اجرا نمی شود.
اگر مدیریت استخر مورد نیاز نباشد و لیست کارهای برنامه ریزی شده خالی نباشد، کارگر شروع به اجرای آنها می کند. ما به طور متعارف چنین کارگرانی را می نامیم در حال اجرا.
در صورت لزوم، کارگر نقش را بر عهده می گیرد مدیراستخر. یک استخر می تواند فقط یک کارگر مدیر داشته باشد یا اصلاً کارگر نداشته باشد. وظیفه آن حفظ تعداد بهینه کارگران در هر استخر است. او چگونه این کار را انجام می دهد؟ اولاً کارگرانی که برای مدت طولانی بیکار بوده اند حذف می شوند. ثانیاً، اگر سه شرط به طور همزمان برآورده شود، کارگران جدید ایجاد می شوند:
- هنوز کارهایی برای تکمیل وجود دارد (کارها در استخر)
- بدون کارگر بیکار
- هیچ کارگر شاغلی وجود ندارد (یعنی فعال و بدون خواب)
حسابداری کارگران شاغل مستقیماً از زمانبندی هسته اصلی لینوکس انجام میشود. این مکانیسم کنترلی سطح همزمانی بهینه را تضمین میکند، از ایجاد تعداد زیادی کارگر در صف کار جلوگیری میکند، اما باعث نمیشود که کار برای مدت طولانی بیمورد منتظر بماند.
علاقه مندان می توانند به تابع worker در هسته نگاه کنند که به آن worker_thread() می گویند.
تمام توابع و ساختارهای توصیف شده را می توان با جزئیات بیشتر در فایل ها یافت include/linux/workqueue.h, هسته/صف کار.cو kernel/workqueue_internal.h. همچنین مستنداتی در مورد صف کار در وجود دارد Documentation/workqueue.txt.
همچنین شایان ذکر است که مکانیسم صف کاری در هسته نه تنها برای پردازش وقفه های معوق استفاده می شود (اگرچه این یک سناریوی نسبتاً رایج است).
بنابراین، ما به مکانیسمهای مدیریت وقفههای معوق در هسته لینوکس - tasklet و workqueue که شکل خاصی از چندوظیفگی هستند، نگاه کردیم. میتوانید در مورد وقفهها، تسکلتها و صفهای کاری در کتاب «درایورهای دستگاه لینوکس» نوشته جاناتان کوربت، گرگ کروآ-هارتمن، الساندرو روبینی، اطلاعاتی که در آنجا وجود دارد گاهی قدیمی است.