خانه - مرورگرها
برنامه نویسی چند وظیفه ای در لینوکس. برنامه نویسی لینوکس چند وظیفه ای پس زمینه و مدیریت فرآیند اولویت

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

لینوکس در ابتدا توسط لینوس توروالدز نوشته شد و سپس توسط افراد بی شماری در سراسر جهان بهبود یافت. این یک شبیه سازی از سیستم عامل یونیکس، یکی از اولین سیستم عامل های قدرتمند است که برای رایانه ها توسعه یافته است، اما رایگان نیست. اما نه آزمایشگاه های سیستم یونیکس، خالقان یونیکس، و نه دانشگاه برکلی، توسعه دهندگان توزیع نرم افزار برکلی (BSD)، در ایجاد آن دخیل نبودند. یکی از مهمترین حقایق جالباز تاریخچه لینوکس این است که مردم از سراسر جهان به طور همزمان در ایجاد آن - از استرالیا تا فنلاند - شرکت کردند و تا به امروز ادامه می دهند.

لینوکس در ابتدا برای اجرا بر روی پردازنده 386 طراحی شده بود. یکی از اولین پروژه های لینوس توروالدز برنامه ای بود که می توانست بین فرآیندها جابجا شود، یکی از آنها AAAA و دیگری BBBB چاپ می کرد. این برنامه متعاقباً به لینوکس تبدیل شد. درست تر است که بگوییم لینوس هسته سیستم عامل را توسعه داده است و او مسئول پایداری آن است.

لینوکس از اکثر یونیکس های محبوب پشتیبانی می کند نرم افزار، شامل سیستم گرافیکیپنجره X - و این تعداد زیادی برنامه است، اما باید تاکید کرد که لینوکس کاملا رایگان است. بیشترین هزینه ای که باید برای آن بپردازید بسته بندی و سی دی است که توزیع لینوکس روی آن ضبط شده است. یک توزیع، خود سیستم عامل + مجموعه ای از بسته های نرم افزاری برای لینوکس است. همچنین لازم به ذکر است که همه اینها با کد منبع ارائه می شود و هر برنامه ای که تحت لینوکس نوشته شده است را می توان مطابق با نیازهای شما تغییر داد. این همچنین به شما امکان می دهد هر برنامه ای را به هر پلتفرمی - Intel PC، Macintosh منتقل کنید. به هر حال، همه موارد فوق به لطف بنیاد نرم افزار آزاد، یک صندوق، اتفاق افتاد برنامه های رایگان، که بخشی از پروژه گنو است. و به همین منظور است که GPL - مجوز عمومی عمومی - ایجاد شد که بر اساس آن لینوکس مانند همه نرم افزارهای آن رایگان است و استفاده تجاری از نرم افزار برای لینوکس یا قطعات آن ممنوع است. سیستم پیکربندی یونیکس لینوکس

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

امروزه توسعه لینوکس دو شاخه را دنبال می کند. نسخه اول، با شماره های زوج (2.0، 2.2، 2.4)، نسخه پایدارتر و قابل اعتماد لینوکس در نظر گرفته می شود. نسخه دوم که نسخه های آن با اعداد فرد شماره گذاری شده اند (2.1، 2.3)، جسورتر و سریعتر در حال توسعه است و بنابراین (متاسفانه) باگ تر است. اما این یک موضوع سلیقه ای است.

در لینوکس جدایی وجود ندارد درایوهای C, D، و فرآیند ارتباط با دستگاه ها بسیار راحت است. همه دستگاه ها خود را دارند فایل سیستمی، همه دیسک ها به یک سیستم فایل متصل هستند و همه یکپارچه به نظر می رسند، یکی. ساختار دایرکتوری واضح به شما امکان می دهد هر اطلاعاتی را فوراً پیدا کنید. برای فایل‌های کتابخانه - دایرکتوری خودش، برای فایل‌های راه‌اندازی - خودش، برای فایل‌های با تنظیمات - خودش، برای فایل‌های دستگاه - خودش، و غیره.

ماژولار بودن هسته به شما این امکان را می دهد که بدون راه اندازی مجدد رایانه، هر سرویس سیستم عامل را متصل کنید. علاوه بر این، می توانید خود هسته سیستم عامل را بازسازی کنید، زیرا کدهای منبع هسته نیز در هر توزیعی موجود هستند.

سیستم عامل لینوکس بسیار ماهرانه، به اصطلاح، از ایده چند وظیفه ای استفاده می کند، یعنی. هر فرآیندی در سیستم به طور همزمان اجرا می شود (مقایسه با ویندوز: کپی کردن فایل ها در فلاپی دیسک و تلاش برای گوش دادن به موسیقی در این لحظه همیشه سازگار نیست).

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

در سال 1998، لینوکس سریعترین سیستم عامل سرور در حال رشد بود، با افزایش 212 درصدی در آن سال. امروزه بیش از 20000000 کاربر لینوکس وجود دارد. تحت لینوکس برنامه های زیادی برای هر دو طراحی شده است استفاده خانگیو برای ایستگاه های کاری یونیکس و سرورهای اینترنتی کاملاً کاربردی.

لینوکس دیگر فقط یک سیستم عامل نیست. لینوکس بیشتر و بیشتر شبیه یک فرقه می شود. رسیدن به حقیقت در مورد یک فرقه روز به روز دشوارتر می شود. بیایید با واقعیت ها شروع کنیم. بنابراین لینوکس این است:

  • * کلون یونیکس رایگان (یا بهتر است بگوییم آزادانه توزیع شده)؛
  • * سیستم عامل با چند وظیفه واقعی.
  • * سیستم‌عاملی که هر «کاربر» می‌تواند آن را تغییر دهد، زیرا می‌توانید کدهای منبع را تقریباً برای هر بخشی از آن پیدا کنید.
  • * که دقیقاً همانطور که می خواهید پیکربندی شده است، و نه آنطور که سازنده ترجیح می دهد.

تازه کارها در لینوکس در درجه اول جذب این واقعیت هستند که "باحال" و مد روز است. افسانه ای وجود دارد که این سیستم عامل واقعاً برای کاربر نهایی مناسب نیست. به منظور مونتاژ یک سرور قابل اعتماد و مقاوم در برابر هک، این بیش از تصمیم خوب، اما نه برای کاربر سادهکسی که به راحتی، راحتی نیاز دارد و اصلاً نمی خواهد سیستمی را که در حال حاضر با آن کار می کند درک و احساس کند. این کاملا درست نیست. استفاده از سیستم لینوکس سفارشی با رابط گرافیکی به آسانی و بصری بودن سیستم عامل مایکروسافت است. درست است که راه اندازی لینوکس به تلاش و دانش زیادی نیاز دارد.

در نتیجه این ویژگی های ایجاد و توسعه، لینوکس "ویژگی های شخصیت" بسیار خاصی را به دست آورد. از یک طرف، این یک سیستم یونیکس معمولی، چند کاربره و چند وظیفه ای است. از سوی دیگر، یک سیستم معمولی از هکرها، دانش‌آموزان و به طور کلی هر فردی وجود دارد که دوست دارد به طور مداوم همه چیز را تا ریزترین جزئیات یاد بگیرد و بفهمد. انعطاف پذیری راه اندازی و استفاده از لینوکس احتمالاً مشابه نیست. می توانید از آن در سطحی که win95 کار می کند استفاده کنید - یعنی یک دسکتاپ گرافیکی با تمام ویژگی های آن در ویندوز داشته باشید: نمادها، نوار وظیفه، منوی زمینهو غیره. علاوه بر این، می توانید یک دسکتاپ نصب کنید که هیچ تفاوتی در آن نخواهد داشت ظاهرو توابع از ویندوز. (به طور کلی، گزینه ها مدیران پنجرهتحت لینوکس به سادگی هیچ پایانی وجود ندارد، از icewm فوق‌العاده اسپارتان گرفته تا Enlightment + Gnome فوق‌العاده پیچیده). از سوی دیگر، لینوکس به شما دسترسی بی سابقه ای به سخت افزار در هر سطحی از در دسترس بودن می دهد. درست است، برای این کار کافی نیست که بتوانید دکمه سمت راست ماوس را کف بزنید؛ باید SI و معماری کامپیوتر را یاد بگیرید. اما شخصی که زمانی این بوی فکر، این الهام یک برنامه نویس را احساس می کرد، وقتی ماشینی را "کنار گوش" می گیرید و می توانید با آن به معنای واقعی کلمه هر کاری را که می تواند انجام دهد - چنین شخصی هرگز نمی تواند به آن بازگردد. پنجه های نرم ویندوز

اگر هنگام استفاده از یک سیستم عامل تجاری، کاربر مجبور شود منتظر انتشار نسخه بعدی باشد تا سیستمی بدون اشکال و باگ نسخه قبلی دریافت کند، ماژولار بودن لینوکس به شما امکان می دهد یک هسته جدید را دانلود کنید. که حداقل هر دو ماه یک بار یا حتی بیشتر (نسخه پایدار) منتشر می شود.

پاسخ به سوال لینوکس چیست؟ شما می توانید بسیاری را پیدا کنید. بسیاری از مردم بر این باورند که لینوکس فقط یک هسته است. اما هسته به تنهایی هیچ فایده ای برای کاربر ندارد. اگرچه هسته بدون شک اساس سیستم عامل لینوکس است، کاربر باید همیشه با برنامه های کاربردی کار کند. اهمیت این برنامه ها کمتر از هسته نیست. بنابراین لینوکس مجموعه ای از هسته و برنامه های کاربردی اصلی است که معمولا بر روی هر کامپیوتری با این سیستم عامل نصب می شود. ترکیب هسته و برنامه های کاربردی در یک کل واحد نیز در نام سیستم منعکس شده است: گنو/لینوکس. گنو پروژه ای است برای ایجاد مجموعه ای از برنامه ها مشابه آنچه معمولاً یک سیستم شبه یونیکس را همراهی می کند.

یکی از شکایت‌های رایج حامیان لینوکس این است که وقتی از مزایای لینوکس صحبت می‌کنند، معایب ویندوز را فهرست می‌کنند. اما این اغلب اجتناب ناپذیر است، زیرا همه چیز با مقایسه آموخته می شود و اکثر کاربران رایانه اکنون فقط با ویندوز آشنا هستند. پس لینوکس چه چیزی به شما می دهد؟

اصل: فرآیندهای سبک وزن: تشریح موضوعات لینوکس
نویسندگان: Vishal Kanaujia، Chetan Giridhar
تاریخ انتشار: 1 آگوست 2011
ترجمه: A. Panin
تاریخ انتشار ترجمه: 22 اکتبر 2012

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

رشته های برنامه عنصر اساسی یک محیط نرم افزاری چندوظیفه ای هستند. یک رشته برنامه را می توان به عنوان محیط اجرای یک فرآیند توصیف کرد. بنابراین، هر فرآیند حداقل یک رشته دارد. Multithreading شامل داشتن محیط های متعدد موازی (در سیستم های چند پردازنده ای) و معمولاً همگام سازی شده برای یک فرآیند است.

رشته های برنامه دارای شناسه های مخصوص به خود هستند (شناسه رشته) و می توانند مستقل از یکدیگر اجرا شوند. آنها یک فضای آدرس فرآیند را با یکدیگر به اشتراک می گذارند و از این ویژگی به عنوان یک مزیت استفاده می کنند و به آنها امکان می دهد از کانال های IPC (سیستم های ارتباط بین پردازشی - حافظه مشترک، لوله ها و سایر سیستم ها) برای تبادل داده خودداری کنند. رشته‌های یک فرآیند می‌توانند تعامل داشته باشند - برای مثال، رشته‌های مستقل می‌توانند مقدار یک متغیر سراسری را دریافت/تغییر دهند. این مدل ارتباطی سربار تماس های IPC را در سطح هسته حذف می کند. از آنجایی که thread ها در یک فضای آدرس واحد عمل می کنند، سوئیچ های بافت رشته سریع هستند و نیازی به منابع ندارند.

هر رشته برنامه را می توان به صورت جداگانه توسط زمانبندی وظیفه پردازش کرد، بنابراین برنامه های کاربردی چند رشته ای برای اجرای موازی در سیستم های چند پردازنده ای مناسب هستند. علاوه بر این، ایجاد و از بین بردن نخ ها سریع است. برخلاف فراخوانی fork()، نخ یک کپی از فضای آدرس فرآیند والد ایجاد نمی‌کند؛ در عوض، رشته‌ها فضای آدرس را همراه با منابع دیگر، از جمله دسته‌های فایل و کنترل‌کننده‌های سیگنال، به اشتراک می‌گذارند.

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

چندین ویژگی جالب

شناخته‌شده‌ترین ویژگی کار با رشته‌ها، همگام‌سازی آن‌ها است، به‌ویژه زمانی که منبع مشترکی وجود دارد که به عنوان بخش مهم علامت‌گذاری شده است. این بخشی از کد است که به یک منبع مشترک دسترسی دارد و در هر زمان نباید بیش از یک رشته در دسترس باشد. از آنجایی که هر رشته می تواند به طور مستقل اجرا شود، دسترسی به منبع مشترک کنترل نمی شود، که منجر به نیاز به استفاده از اصول اولیه همگام سازی، از جمله mutexes (حذف متقابل)، سمافورها، قفل های خواندن/نوشتن و موارد دیگر می شود.

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

Thread ها در لینوکس چگونه پیاده سازی می شوند؟

لینوکس به شما امکان توسعه و استفاده از برنامه های چند رشته ای را می دهد. در سطح کاربر، پیاده سازی رشته ها در لینوکس از استاندارد باز POSIX (رابط سیستم عامل قابل حمل برای یونیکس) پیروی می کند. سیستم های یونیکسکتابخانه سطح کاربر (glibc.so در اوبونتو) پیاده‌سازی API POSIX را برای رشته‌ها فراهم می‌کند.

در لینوکس، موضوعات برنامه در دو فضای مجزا وجود دارد - فضای کاربر و فضای هسته. در فضای کاربر، رشته ها با استفاده از API کتابخانه pthread سازگار با POSIX ایجاد می شوند. این رشته‌های فضای کاربر به‌طور جدایی‌ناپذیری با رشته‌های فضای هسته مرتبط هستند. در لینوکس، رشته های فضای هسته به عنوان "فرایندهای سبک وزن" در نظر گرفته می شوند. یک فرآیند سبک وزن واحدی از محیط اصلی زمان اجرا است. بر خلاف انواع مختلف یونیکس، از جمله سیستم هایی مانند HP-UX و SunOS، لینوکس یک سیستم نخ جداگانه ندارد. یک فرآیند یا رشته در لینوکس به عنوان یک "وظیفه" در نظر گرفته می شود و از همان ساختارهای داخلی (یک سری از ساختارهای struct task_structs) استفاده می کند.

برای تعدادی از موضوعات فرآیند ایجاد شده در فضای کاربر، تعدادی فرآیند سبک وزن مرتبط با آنها در هسته وجود دارد. یک مثال این نکته را نشان می دهد: #include #عبارتند از #عبارتند از Int main() (pthread_t tid = pthread_self(); int sid = syscall(SYS_gettid)؛ printf("شناسه LWP %dn است"، sid)؛ printf("شناسه موضوع POSIX %dn است"، tid)؛ بازگشت 0. )

با استفاده از ابزار ps، می توانید اطلاعاتی در مورد فرآیندها و همچنین فرآیندهای سبک وزن این فرآیندها دریافت کنید: kanaujia@ubuntu:~/Desktop$ ps -fL UID PID PPID LWP C NLWP STIME TTY TIME CMD kanaujia 17281 5191 172 Jun11 pts/ 2 00:00:02 bash kanaujia 22838 17281 22838 0 1 08:47 pts/2 00:00:00 ps -fL kanaujia 17647 14111 172pts0006 172400006 17280000000 . س

فرآیندهای سبک وزن چیست؟

فرآیند سبک وزن فرآیندی است که از رشته فضای کاربر پشتیبانی می کند. هر رشته فضای کاربری به طور جدایی ناپذیری با یک فرآیند سبک مرتبط است. روش ایجاد یک فرآیند سبک وزن با روش ایجاد یک فرآیند معمولی متفاوت است. فرآیند کاربر "P" ممکن است تعدادی فرآیند سبک مرتبط با همان شناسه گروه داشته باشد. گروه بندی به هسته اجازه می دهد تا منابع را پارتیشن بندی کند (منابع شامل فضای آدرس، صفحات است حافظه فیزیکی(VM)، کنترل کننده سیگنال و توصیف کننده فایل). این همچنین به هسته این امکان را می دهد که هنگام برخورد با این فرآیندها از سوئیچ های زمینه اجتناب کند. به اشتراک گذاری منابع جامع دلیلی است که به این فرآیندها سبک وزن می گویند.

لینوکس چگونه فرآیندهای سبک وزن ایجاد می کند؟

که در ایجاد لینوکسفرآیندهای سبک وزن با استفاده از فراخوانی سیستم ()کلون غیر استاندارد اجرا می شوند. این شبیه به fork()، اما با عملکرد بیشتر است. به طور کلی، فراخوانی fork() با استفاده از فراخوانی clone() با اجرا می شود پارامترهای اضافی، نشان دهنده منابعی است که بین فرآیندها به اشتراک گذاشته خواهد شد. فراخوانی clone() فرآیندی را ایجاد می کند که فرزند عناصر زمان اجرا را با والد به اشتراک می گذارد، از جمله حافظه، دسته فایل ها و کنترل کننده های سیگنال. کتابخانه pthread همچنین از فراخوانی clone() برای پیاده سازی thread ها استفاده می کند. به فایل کد منبع مراجعه کنید ./nptl/sysdeps/pthread/createthread.cدر دایرکتوری کد منبع glibc نسخه 2.11.2.

فرآیند سبک وزن خود را ایجاد کنید

بیایید نمونه ای از استفاده از فراخوانی ()clone را نشان دهیم. نگاه کنید منبعاز فایل demo.c زیر:

#عبارتند از #عبارتند از #عبارتند از #عبارتند از #عبارتند از #عبارتند از #عبارتند از //اندازه پشته 64 کیلوبایت #define STACK 1024*64 // رشته فرزند این تابع را اجرا خواهد کرد int threadFunction(void* argument) ( printf("رشته فرزند وارد می شود\n"); close((int*)argument); printf( "رشته خروجی فرزند\n"؛ بازگشت 0؛ ) int main() (پشته خالی*؛ pid_t pid؛ int fd؛ fd = open("/dev/null"، O_RDWR)؛ اگر (fd< 0) { perror("/dev/null"); exit(1); } // Резервирование памяти для стека stack = malloc(STACK); if (stack == 0) { perror("malloc: could not allocate stack"); exit(1); } printf("Creating child thread\n"); // Вызов clone() для создания дочернего потока pid = clone(&threadFunction, (char*) stack + STACK, SIGCHLD | CLONE_FS | CLONE_FILES |\ CLONE_SIGHAND | CLONE_VM, (void*)fd); if (pid == -1) { perror("clone"); exit(2); } // Ожидание завершения дочернего потока pid = waitpid(pid, 0, 0); if (pid == -1) { perror("waitpid"); exit(3); } // Попытка записи в файл закончится неудачей, так как поток // закрыл файл if (write(fd, "c", 1) < 0) { printf("Parent:\t child closed our file descriptor\n"); } // Освободить память, используемую для стека free(stack); return 0; }

برنامه demo.c به شما این امکان را می دهد که رشته ها را به روشی مشابه کتابخانه pthread ایجاد کنید. با این حال، استفاده از فراخوانی clone() به طور مستقیم توصیه نمی شود زیرا در صورت استفاده نادرست، برنامه در حال توسعه ممکن است با شکست مواجه شود. سینتکس تابع clone() در لینوکس در زیر آورده شده است: #include int clone (int (*fn) (void *), void *child_stack, int flags, void *arg);

اولین آرگومان تابع thread است. زمانی که thread شروع می شود فراخوانی می شود. پس از اینکه فراخوانی clone() با موفقیت کامل شد، تابع fn همزمان با فراخوانی اجرا می شود.

آرگومان بعدی یک اشاره گر به یک مکان حافظه برای پشته پردازش فرزند است. مرحله قبل از فراخوانی fork() و clone() به برنامه نویس نیاز دارد که حافظه را رزرو کند و یک اشاره گر را برای استفاده به عنوان پشته پردازش فرزند ارسال کند، زیرا پردازش های والد و فرزند صفحات حافظه را به اشتراک می گذارند - این شامل پشته است. یک پردازش فرزند می تواند تابعی متفاوت از فرآیند والد را فراخوانی کند، به همین دلیل است که یک پشته جداگانه مورد نیاز است. در برنامه ما، این قطعه از حافظه را با استفاده از تابع malloc() روی پشته ذخیره می کنیم. اندازه پشته روی 64 کیلوبایت تنظیم شد. از آنجایی که پشته x86 به سمت پایین رشد می کند، لازم است رفتار مشابه با استفاده از حافظه اختصاص داده شده از انتهای بخش شبیه سازی شود. به همین دلیل آدرس زیر را به تابع clone() منتقل می کنیم: (char*) stack + STACK

بحث پرچم های بعدی به ویژه مهم است. به شما امکان می دهد مشخص کنید کدام منابع باید با فرآیند ایجاد شده به اشتراک گذاشته شود. ما بیت ماسک را انتخاب کردیم SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VMدر زیر شرح داده شده است:

  • SIGCHLD: thread سیگنال SIGCHLD را پس از خاتمه به فرآیند والد ارسال می کند. تنظیم این گزینه به فرآیند والد اجازه می دهد تا از تابع wait() برای منتظر ماندن برای تکمیل تمام رشته ها استفاده کند.
  • CLONE_FS: اطلاعات سیستم فایل را بین فرآیند والد و رشته به اشتراک بگذارید. اطلاعات شامل روت است سیستم فایل، دایرکتوری کاری و مقدار umask.
  • CLONE_FILES: جدول توصیفگر فایل را بین فرآیند والد و رشته به اشتراک بگذارید. تغییرات جدول در فرآیند والد و همه رشته ها منعکس می شود.
  • CLOSE_SIGHAND: جدول کنترل کننده سیگنال را بین فرآیندهای والد و فرزند به اشتراک بگذارید. مجدداً، اگر فرآیند والد یا یکی از رشته ها، کنترل کننده سیگنال را تغییر دهد، این تغییر در جداول سایر فرآیندها منعکس خواهد شد.
  • CLONE_VM: فرآیند والد و رشته ها در فضای حافظه یکسانی اجرا می شوند. تمام نوشته های حافظه یا نگاشت هایی که توسط یکی از آنها انجام می شود برای سایر فرآیندها در دسترس است.

آخرین پارامتر آرگومان ارسال شده به تابع (ThreadFunction)، در مورد ما یک توصیفگر فایل است.

لطفاً به مثال کار با فرآیندهای سبک demo.c که قبلاً منتشر کردیم مراجعه کنید.

موضوع فایل (/dev/null) باز شده توسط فرآیند والد را می بندد. از آنجایی که فرآیند والد و رشته جدول توصیفگر فایل را به اشتراک می گذارند، عملیات بسته شدن فایل بر فرآیند والد نیز تأثیر می گذارد و باعث می شود که فراخوانی های ()write بعدی با شکست مواجه شوند. فرآیند والد منتظر می ماند تا thread خاتمه یابد (لحظه ای که سیگنال SIGCHLD را دریافت می کند). پس از آن، حافظه رزرو شده را آزاد می کند و کنترل را برمی گرداند.

طبق معمول برنامه را کامپایل و اجرا کنید. خروجی باید مشابه تصویر زیر باشد: $gcc demo.c $./a.out ایجاد رشته فرزند رشته فرزند ورود به رشته فرزند خروج والد: فرزند توصیف کننده فایل ما را بست $

لینوکس از یک زیرساخت threading کارآمد، ساده و مقیاس پذیر پشتیبانی می کند. این امر علاقه برنامه نویسان را به آزمایش و توسعه کتابخانه های رشته ای که از clone() به عنوان یک تابع اصلی استفاده می کنند، برانگیخته است.

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

مقالات این مجموعه:

  1. چند وظیفه ای در هسته لینوکس: صف کاری

صف کار

صف کار- این ها موجودیت های پیچیده تر و سنگین تری نسبت به 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
باید توجه ویژه ای به پرچم داشت WQ_UNBOUND. بر اساس وجود این پرچم، صف ها به دو دسته محدود و بدون اتصال تقسیم می شوند.
در صف های مرتبطوقتی اضافه می‌شود، کارها به 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 آشنا شدیم، بیایید سعی کنیم با جزئیات بیشتر نحوه عملکرد و مدیریت آن را درک کنیم.
هر استخر دارای مجموعه ای از کارگران است که وظایف را انجام می دهند. علاوه بر این، تعداد کارگران به طور پویا تغییر می کند و با شرایط فعلی سازگار می شود.
همانطور که قبلا متوجه شدیم، کارگران رشته هایی هستند که کار را در زمینه هسته انجام می دهند. کارگر آنها را به ترتیب، یکی پس از دیگری، از استخر کارگر مرتبط با خود بازیابی می کند، و کارگران، همانطور که قبلاً می دانیم، می توانند به صف های منبع مختلف تعلق داشته باشند.

کارگران به طور مشروط می توانند در سه حالت منطقی باشند: آنها می توانند بیکار، در حال اجرا یا مدیریت باشند.
کارگر می تواند بیکار بایستو هیچ کاری نکن به عنوان مثال، این زمانی است که همه کارها قبلاً در حال اجرا هستند. وقتی یک کارگر وارد این حالت می شود، به خواب می رود و بر این اساس، تا زمانی که از خواب بیدار نشود، اجرا نمی شود.
اگر مدیریت استخر مورد نیاز نباشد و لیست کارهای برنامه ریزی شده خالی نباشد، کارگر شروع به اجرای آنها می کند. ما به طور متعارف چنین کارگرانی را می نامیم در حال اجرا.
در صورت لزوم، کارگر نقش را بر عهده می گیرد مدیراستخر. یک استخر می تواند فقط یک کارگر مدیر داشته باشد یا اصلاً کارگر نداشته باشد. وظیفه آن حفظ تعداد بهینه کارگران در هر استخر است. او چگونه این کار را انجام می دهد؟ اولاً کارگرانی که برای مدت طولانی بیکار بوده اند حذف می شوند. ثانیاً، اگر سه شرط به طور همزمان برآورده شود، کارگران جدید ایجاد می شوند:

  • هنوز کارهایی برای تکمیل وجود دارد (کارها در استخر)
  • بدون کارگر بیکار
  • هیچ کارگر شاغلی وجود ندارد (یعنی فعال و بدون خواب)
با این حال، آخرین شرط تفاوت های ظریف خاص خود را دارد. اگر صف‌های استخر متصل نباشند، کارگران در حال اجرا در نظر گرفته نمی‌شوند؛ برای آنها این شرط همیشه صادق است. همین امر در مورد کارگری که وظیفه ای را از یک کار مرتبط، اما با پرچم اجرا می کند، صادق است. WQ_CPU_INTENSIVE، صف ها علاوه بر این، در مورد صف های گره خورده، از آنجایی که کارگران با کارهایی از استخر مشترک (که برای هر هسته در تصویر بالا یکی از دو مورد است) کار می کنند، معلوم می شود که برخی از آنها کار حساب می شوند و برخی نه. همچنین نتیجه می شود که انجام کار از WQ_CPU_INTENSIVEصف ها ممکن است بلافاصله شروع نشوند، اما خود آنها در اجرای کارهای دیگر دخالت نمی کنند. اکنون باید مشخص شود که چرا این پرچم به این نام خوانده می شود و چرا زمانی که انتظار داریم کار طولانی مدت طول بکشد از آن استفاده می شود.

حسابداری کارگران شاغل مستقیماً از زمان‌بندی هسته اصلی لینوکس انجام می‌شود. این مکانیسم کنترلی سطح همزمانی بهینه را تضمین می‌کند، از ایجاد تعداد زیادی کارگر در صف کار جلوگیری می‌کند، اما باعث نمی‌شود که کار برای مدت طولانی بی‌مورد منتظر بماند.

علاقه مندان می توانند به تابع worker در هسته نگاه کنند که به آن worker_thread() می گویند.

تمام توابع و ساختارهای توصیف شده را می توان با جزئیات بیشتر در فایل ها یافت include/linux/workqueue.h, هسته/صف کار.cو kernel/workqueue_internal.h. همچنین مستنداتی در مورد صف کار در وجود دارد Documentation/workqueue.txt.

همچنین شایان ذکر است که مکانیسم صف کاری در هسته نه تنها برای پردازش وقفه های معوق استفاده می شود (اگرچه این یک سناریوی نسبتاً رایج است).

بنابراین، ما به مکانیسم‌های مدیریت وقفه‌های معوق در هسته لینوکس - tasklet و workqueue که شکل خاصی از چندوظیفگی هستند، نگاه کردیم. می‌توانید در مورد وقفه‌ها، تسک‌لت‌ها و صف‌های کاری در کتاب «درایورهای دستگاه لینوکس» نوشته جاناتان کوربت، گرگ کروآ-هارتمن، الساندرو روبینی، اطلاعاتی که در آنجا وجود دارد گاهی قدیمی است.

کار آزمایشگاهی شماره 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. برای اشکال زدایی برنامه ها، استفاده از ویرایشگر داخلی مدیر فایل Midnight Commander (MC) راحت است که ساختارهای مختلف زبان را با رنگ برجسته می کند و موقعیت مکان نما را در فایل (ردیف، ستون) در خط بالایی نشان می دهد. از صفحه نمایش

3.3. مدیر فایل Midnight Commander دارای یک بافر فرمان است که می توان آن را با یک میانبر صفحه کلید فراخوانی کرد - H، که با استفاده از فلش های مکان نما (بالا و پایین) قابل جابجایی است. برای درج یک فرمان از بافر در خط فرمان، از کلید استفاده کنید ، برای ویرایش یک دستور از کلیدهای بافر<- и ->, و .


3.4. به یاد داشته باشید که دایرکتوری فعلی در مسیر موجود نیست، بنابراین از خط فرمانباید برنامه را به صورت "./print_pid" اجرا کنید. در MC، فقط ماوس را روی فایل ببرید و کلیک کنید .

3.5. برای مشاهده نتیجه اجرای برنامه از میانبر صفحه کلید استفاده کنید - O. آنها همچنین در حالت ویرایش فایل کار می کنند.

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. چگونه یک فرآیند را در سیستم عامل و برنامه از بین ببریم؟

دستور زیر را در پوسته خود تایپ کنید:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

لیستی از تمام فرآیندهای در حال اجرا در سیستم روی صفحه نمایش داده می شود. اگر می‌خواهید تعداد فرآیندها را بشمارید، چیزی شبیه به زیر تایپ کنید:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ ps -e --no-headers | nl | دم -n 1

74 4650 pts/0 00:00:00 دم

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

عدد اول تعداد فرآیندهای در حال اجرا در سیستم است. کاربران KDE می توانند از برنامه kpm استفاده کنند و کاربران Gnome می توانند از برنامه gnome-system-monitor برای به دست آوردن اطلاعات در مورد فرآیندها استفاده کنند. لینوکس برای همین است که به کاربر اجازه می دهد همین کار را انجام دهد راه های مختلف.

این سوال مطرح می شود: "فرآیند چیست؟" فرآیندها در لینوکس، مانند فایل ها، مفاهیم بدیهی هستند. گاهی اوقات فرآیند با شناسایی می شود برنامه در حال اجرااما همیشه هم به این صورت نیست. بیایید فرض کنیم که یک فرآیند واحد کاری یک سیستم است که کاری را انجام می دهد. چندوظیفه ای توانایی چندین فرآیند به طور همزمان در یک سیستم است.

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

برخی از فرآیندها می توانند فرآیندهای دیگری را ایجاد کنند و ساختار درختی را تشکیل دهند. فرآیندهای تولیدی را والدین یا فرآیندهای والد و به کودکان فرآیندهای فرزند یا فرزند می گویند. در بالای این "درخت" فرآیند init قرار دارد که به طور خودکار توسط هسته در طول فرآیند بوت سیستم ایجاد می شود.

هر فرآیند در سیستم با یک جفت اعداد صحیح غیر منفی مرتبط است: یک شناسه فرآیند PID (شناسه فرآیند) و یک شناسه فرآیند والد PPID (شناسه فرآیند والد). برای هر فرآیند، PID منحصر به فرد است (در یک نقطه خاص از زمان)، و PPID برابر با شناسه فرآیند والد است. اگر دستور ps -ef را در پوسته وارد کنید، لیستی از فرآیندها با مقادیر PID و PPID آنها (به ترتیب ستون های دوم و سوم) نمایش داده می شود. نمونه ای از این دستور:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

UID PID PPID C STIME TTY TIME CMD

ریشه 1 0 0 17:08؟ 00:00:00 /sbin/init

ریشه 2 0 0 17:08؟ 00:00:00

ریشه 3 2 0 17:08؟ 00:00:00

ریشه 4 2 0 17:08؟ 00:00:00

ریشه 5 2 0 17:08؟ 00:00:00

ریشه 6 2 0 17:08؟ 00:00:00

ریشه 7 2 0 17:08؟ 00:00:00

ریشه 8 2 0 17:08؟ 00:00:00

ریشه 9 2 0 17:08؟ 00:00:00

ریشه 10 2 0 17:08؟ 00:00:00

ریشه 11 2 0 17:08؟ 00:00:00

ریشه 12 2 0 17:08؟ 00:00:00

ریشه 13 2 0 17:08؟ 00:00:00

ریشه 14 2 0 17:08؟ 00:00:00

ریشه 15 2 0 17:08؟ 00:00:00

ریشه 16 2 0 17:08؟ 00:00:00

ریشه 17 2 0 17:08؟ 00:00:00

ریشه 18 2 0 17:08؟ 00:00:00

ریشه 19 2 0 17:08؟ 00:00:00

df00 16389 16387 0 20:10 pts/1 00:00:00 /bin/bash

df00 17446 2538 0 20:26؟ 00:00:00

df00 18544 2932 0 20:41 pts/2 00:00:00 /bin/bash -l

df00 19010 18544 0 20:48 pts/2 00:00:00 ps -ef

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

لازم به ذکر است که فرآیند init همیشه دارای شناسه 1 و PPID 0 است. اگرچه در واقعیت هیچ فرآیندی با شناسه 0 وجود ندارد. درخت فرآیند را می توان با استفاده از گزینه --forest برنامه ps نیز تجسم کرد:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

2؟ 00:00:00 kthreadd

3 ?00:00:00 \_ migration/0

4 ?00:00:00 \_ ksoftirqd/0

5 ?00:00:00 \_ سگ نگهبان/0

6 ?00:00:00 \_ مهاجرت/1

7 ?00:00:00 \_ ksoftirqd/1

8 ?00:00:00 \_ سگ نگهبان/1

9 ?00:00:00 \_ events/0

10 ?00:00:00 \_ رویداد/1

11 ?00:00:00 \_ cpuset

12 ?00:00:00 \_ khelper

13 ?00:00:00 \_ netns

14 ?00:00:00 \_ async/mgr

15 ?00:00:00 \_ kintegrityd/0

16 ?00:00:00 \_ kintegrityd/1

18544 pts/2 00:00:00 \_ bash

16388 ?00:00:00 \_ gnome-pty-helpe

16389 pts/1 00:00:00 \_ bash

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

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

استفاده از getpid() و getppid()

یک فرآیند می تواند PID خود و همچنین PPID والد خود را با استفاده از فراخوانی های سیستم getpid() و getppid() پیدا کند.

فراخوانی های سیستم getpid() و getppid() دارای نمونه های اولیه زیر هستند:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

pid_t getpid(void);

pid_t getppid(void);

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

برای استفاده از getpid() و getppid()، فایل های هدر unistd.h و sys/types.h (برای نوع pid_t) باید با استفاده از دستور #include در برنامه گنجانده شوند. فراخوانی getpid() شناسه فرآیند جاری (PID) و getppid() شناسه والد (PPID) را برمی گرداند. pid_t یک نوع عدد صحیح است که ابعاد آن به سیستم خاص بستگی دارد. مقادیر این نوع را می توان به عنوان اعداد صحیح معمولی از نوع int استفاده کرد.

حال بیایید در نظر بگیریم یک برنامه ساده، که PID و PPID را نمایش می دهد و سپس تا زمانی که کاربر فشار دهد ثابت می شود .

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

#عبارتند از

#عبارتند از

#عبارتند از

pid_t pid, ppid;

pid = getpid();

ppid = getppid();

printf("PID: %d\n"، pid);

printf("PPID: %d\n"، ppid);

fprintf(stderr، "فشار دهید خارج شدن...")؛

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

حال بیایید بررسی کنیم که این برنامه چگونه کار می کند. برای انجام این کار، بیایید آن را کامپایل و اجرا کنیم:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ gcc -o getpid getpid.c

مطبوعات خارج شدن...

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

حالا بدون فشار دادن ، پنجره ترمینال دیگری را باز کنید و بررسی کنید که فراخوانی های سیستم getpid() و getppid() به درستی کار می کنند:

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

$ ps -ef | گرپ گپید

df00 19724 19702 0 20:58 pts/3 00:00:00 ./اصلی

df00 19856 18544 0 21:00 pts/2 00:00:00 grep --colour=auto main

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−



 


خواندن:



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

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

آیا می توان گوش های یونیورسال را با قیمت ارزان خریداری کرد؟ 3000 روبل - آیا می توان برای چنین پولی هدفون های باکیفیت خریداری کرد؟ همانطور که معلوم شد، بله. و گفتار...

دوربین اصلی موبایل معمولاً در پشت بدنه قرار دارد و برای گرفتن عکس و فیلم استفاده می شود

دوربین اصلی موبایل معمولاً در پشت بدنه قرار دارد و برای گرفتن عکس و فیلم استفاده می شود

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

چگونه با حفظ شماره خود به اپراتور دیگری سوئیچ کنید

چگونه با حفظ شماره خود به اپراتور دیگری سوئیچ کنید

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

بررسی یک فبلت، گران، اما بسیار شایسته

بررسی یک فبلت، گران، اما بسیار شایسته

نقد و بررسی یک فبلت گران قیمت اما بسیار شایسته 1394/03/20 من تنها کفاش جهان بدون چکمه، منتقد گوشی هوشمند بدون گوشی هوشمند خودم هستم ....

فید-تصویر RSS