<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های امیررضا ریاحی</title>
        <link>https://virgool.io/feed/@riahiamirreza79</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-07 22:07:50</pubDate>
        <image>
            <url>https://static.virgool.io/images/default-avatar.jpg</url>
            <title>امیررضا ریاحی</title>
            <link>https://virgool.io/@riahiamirreza79</link>
        </image>

                    <item>
                <title>نگاهی بر مدیریت حافظه توسط سیستم‌عامل - حافظه مجازی</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D8%B1-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AD%D8%A7%D9%81%D8%B8%D9%87-%D8%AA%D9%88%D8%B3%D8%B7-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D8%B9%D8%A7%D9%85%D9%84-%D8%AD%D8%A7%D9%81%D8%B8%D9%87-%D9%85%D8%AC%D8%A7%D8%B2%DB%8C-o4qvdwtdwpeu</link>
                <description>در قسمت قبل با مفهوم paging در مدیریت حافظه آشنا شدیم. در این بخش از این مفهوم برای توضیح و تشریح یکی از مهم‌ترین تکنیک‌های مدیریت حافظه در دنیای سیستم‌عامل، یعنی حافظه مجازی، استفاده خواهیم کرد. اما قبل از صحبت کردن درمورد حافظه مجازی، باید با یکی دیگر از مفاهیم کلیدی اما ساده دنیای سیستم‌عامل آشنا شویم به نام swapping.swapping چیست؟ به دلایل متعددی، که بخشی از آن‌ها در پست‌های اخیر ذکر شده، هر دستورالعمل یا instruction که پردازنده نیاز دارد اجرا کند، حتما باید داخل حافظه اصلی کامپیوتر بارگذاری شده باشد. این یعنی پردازنده نمی‌تواند instruction هایی که داخل دیسک (مثلا حافظه HDD یا SSD) ذخیره شده‌اند را مستقیما اجرا کند. این مسئله یک مشکل خیلی بدیهی بوجود می‌آرود و آن عدم وجود حافظه کافی برای اجرا چندین پروسه همزمان است. همچنین در برخی موقعیت‌ها ممکن است پروسه‌هایی وجود داشته باشند، که هنوز تمام ( terminate) نشده‌اند اما فعلا به دلایلی غیرفعال هستند. مثلا منتظر رسیدن ورودی از سمت کاربر یا شبکه هستند یا هر چیز دیگری.در این شرایط، سیستم‌عامل برای استفاده بهینه‌تر از حافظه اصلی، داده‌های این پروسه‌های غیرفعال را به دیسک یا swap space منتقل می‌کند (اصطلاحا swap out)، و از آن حافظه برای پروسه‌های فعالی که حافظه کافی ندارند استفاده می‌کند (اصطلاحا swap in). پروسه P1 از حافظه اصلی خارج می‌شود و پروسه P2 جایگزین آن می‌شودحافظه مجازی یا virtual memory چیست؟حافظه مجازی به بیان خیلی ساده جدا سازی کامل تصویری است که برنامه‌ها و پروسه‌ها از حافظه واقعی و فیزیکی سیستم دارند به طوری که سیستم‌عامل بتواند بخش‌هایی از داده‌های پروسه‌ها را در دیسک نگه دارد. در موارد زیادی دیده می‌شود که بخش‌هایی از برنامه به ندرت استفاده شده‌اند. مثلا بخش‌هایی از برنامه برای جلوگیری از خطاهای احتمالی است، یا قابلیت‌هایی که کاربر ممکن است استفاده نکند. همچنین بعضی اوقات، آرایه‌ها و متغیرهایی که در برنامه تعریف شده‌اند بسیار بزرگ‌تر از مقدار نیاز کاربر هست. در این گونه موارد، سیستم‌عامل سعی می‌کند با استراتژی‌های مختلف، بخشی از برنامه که احتمال استفاده از آن کم است را وارد حافظه اصلی نکند، تا از حافظه استفاده به‌صرفه‌تری کند. تصویر زیر تا حدی نمایان‌گر این شیوه هست.اندازه حافظه مجازی می‌تواند خیلی بیشتر از اندازه حافظه واقعی کامپیوتر باشددر این تکنیک، حافظه logical الزاما با حافظه فیزیکی تطابق ندارد. و ممکن است آدرس‌هایی از حافظه logical به دیسک اشاره کند. در این موارد سیستم‌عامل موظف است که سریعا داده را از دیسک به حافظه اصلی منتقل کند. در ادامه بیشتر به این روند می‌پردازیم. همچنین چیزی داریم به نام virtual address space که آدرس‌های ممکن و قابل استفاده برای هر برنامه خاص است. این فضای آدرس‌دهی، به این دلیل که سیستم‌عامل به طور پویا داده‌ها را از حافظه به دیسک منتقل می‌کند، می‌تواند بسیار بیشتر از مقدار اصلی حافظه کامپیوتر باشد. یعنی مثلا وقتی کل حافظه اصلی ۸ گیگابایت است، هر برنامه فضایی به وسعت ۴ گیگابایت دارد. در روش سنتی، اگر ۲ برنامه با فضای آدرس‌دهی ۴ گیگابایت اجرا کنیم، کل حافظه پر می‌شود. اما سیستم‌عامل‌های امروزی که از حافظه مجازی پشتیبانی می‌کنند می‌توانند تعداد زیادی برنامه را با فضای آدرس‌دهی خیلی بزرگ مدیریت کنند طوری که هیچ‌کدام به مشکل برنخورند. همان‌طور که در تصویر بالاتر نشان داده شده است، حافظه مجازی بزرگ‌تر است از حافظه اصلی (فیزیکی) و مقادیری از داده‌های روی حافظه مجازی، داخل دیسک یا همان backing store هستند. به علاوه، از آنجایی که حافظه مجازی، نگاه برنامه به حافظه را به‌شدت انتزاعی‌تر و ساده‌تر می‌کند، سیستم‌عامل می‌تواند داده‌های یکسانی که چند برنامه به صورت اشتراک استفاده می‌کنند را در یک حافظه واحد نگه‌دارد. چیزی که مشابه آن را در paging هم دیدیم.paging on demandیکی از مرسوم‌ترین روش‌های استفاده شده در پیاده‌سازی حافظه مجازی، paging-on-demand است. وقتی یک برنامه اجرا می‌شود، احتمالا تمام آپشن‌های آن برنامه مورد نیاز نیست. پس لازم نیست که کل برنامه وارد حافظه شود. ابتدا سیستم‌عامل حافظه مجازی برنامه را تخصیص می‌دهد طوری که از نگاه خود برنامه، همه چیز در حافظه است. اما در واقعیت بخش‌هایی از برنامه در دیسک نشسته‌اند و هنوز وارد حافظه نشده‌اند. اجرا برنامه ادامه می‌یابد با حداقل page هایی از برنامه که نیاز دارند در حافظه باشند. هر وقت برنامه به بخشی از داده‌ها یا حافظه نیاز داشت که داخل page  های بارگذاری شده در حافظه نبود، سیستم‌عامل موظف است سریعا این page را از دیسک به حافظه منتقل کند. اصطلاحا به این شرایط page fault گفته می‌شود. یعنی برنامه page ای را بخواهد که هنوز وارد حافظه مجازی نشده.‌page هایی که هنوز وارد حافظه نشده‌اند، در page-table موجود هستند، اما با یک بیت، نشان داده می‌شود که این page در حافظه نیست.همان‌طور که در تصویر نشان داده شده، از نگاه برنامه، تمامی داده‌ها روی حافظه هستند ( حافظه logical) اما در واقعیت این‌طور نیست. و در page-table مشخص است که کدام یک از این page ها آماده برای استفاده هستند یا نه.هر وقت یک page-fault رخ می‌دهد، چند مرحله باید طی شود، تا page مورد نظر از دیسک به حافظه منتقل شود. این مراحل به‌طور مختصر در شکل زیر نمایش داده شده‌اند.بعد از  اینکه page مورد نظر وارد حافظه شد، page-table تصحیح می‌شوداز تصویر بالا واضح است که هزینه پردازشی هر page-fault کم نیست و به ازاء هر page-fault  باید همه این ۶ مرحله طی شود. لذا بهتر است تا حد امکان از رخ دادن page-fault جلوگیری شود.در شدیدترین حالت، می‌توان برنامه را بدون هیچ page بارگذاری شده داخل حافظه اجرا کرد. در این حالت احتمالا در ابتدای برنامه، به ازای هر instruction چند page-fault رخ دهد که بوضوح موجب کند شدن روند اجرا می‌شود. این روند در ادامه بهبود پیدا می‌کند، چون هر چه جلوتر می‌رود page های بیشتری از برنامه داخل حافظه بارگذاری شده‌اند و احتمالا page-fault کمتری رخ خواهد داد. به این روش اصطلاحا pure demand paging گفته می‌شود. یعنی تا وقتی به یک page نیاز نداریم، آن را داخل حافظه بارگذاری نکنیم. </description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Thu, 02 Dec 2021 21:06:24 +0330</pubDate>
            </item>
                    <item>
                <title>نگاهی بر مدیریت حافظه توسط سیستم‌عامل - paging</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D8%B1-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AD%D8%A7%D9%81%D8%B8%D9%87-%D8%AA%D9%88%D8%B3%D8%B7-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D8%B9%D8%A7%D9%85%D9%84-paging-p2o34dwugjvn</link>
                <description>در قسمت قبلی، تخصیص پیوسته حافظه معرفی شد. یکی از مهم‌ترین مشکل‌های این نوع حافظه‌دهی، external-fragmentation بود. یعنی حافظه مقدار کافی فضا خالی برای اجرا یک پروسه را دارد اما این فضا به بخش‌های کوچک بین دیگر بخش‌های اشغال شده حافظه پخش شده و چون یک‌پارچه نیست، نمی‌توان از آن استفاده مفیدی کرد و عملا آن بخش از حافظه از دست رفته. در این نوشتار روش paging معرفی می‌شود، که در آن مشکل external-fragmentation حل شده است. paging چطور کار می‌کند؟در این پست، فرق بین حافظه logical و physical به‌طور اجمالی گفته شد و دیدیم که چیزی که پردازنده و برنامه‌ها از حافظه می‌بینند یک تصویر مجرد (abstract) از حافظه فیزیکی است. جدا بودن حافظه منطقی از حافظه فیزیکی، در اینجا این امکان را به ما می‌دهد، که در لایه فیزیکی، الزاما حافظه به‌طور پیوسته تخصیص داده نشود، اما از نگاه برنامه‌ها، حافظه کاملا پیوسته باشد. اما چطور؟برای این‌کار ابتدا حافظه فیزیکی را به بخش‌های کوچکی به نام frame تقسیم می‌کنیم. مثلا فریم‌های ۴۰۹۶ بایتی. همچنین حافظه منطقی را هم تقسیم می‌کنیم به بخش‌های کوچک‌تر با همان اندازه فریم‌ها. نام هر بخش از حافظه منطقی ‌page می‌گذاریم. حالا وقتی یک برنامه می‌خواهد از حافظه استفاده کند، سیستم‌عامل به تعداد لازم page در اختیار برنامه قرار می‌دهد. این page ها از نگاه برنامه پیوسته هستند. اما لزوما فریم‌های متناظر با page ها، به طور پیوسته در حافظه فیزیکی تخصیص داده نشده‌اند. یعنی دیگر مشکلی نیست که بخش کوچکی از حافظه بین دو بخش اشغال شده خالی مانده باشد. در هر صورت می‌توانیم از آن استفاده کنیم. چون چیزی که برنامه‌ها می‌بینند page ها هستند و نه frame ها. الزاما حافظه در سطح سخت‌افزار پیوسته و منظم چیده نشده است.اینکار ایجاب می‌کند که برای هربار دسترسی به حافظه، آدرس حافظه توسط MMU ترجمه شود. چون برنامه‌ها از حافظه  منطقی استفاده می‌کنند اما برای دسترسی به داده‌ها باید این آدرس حافظه به حافظه فیزیکی ترجمه شود.برای ترجمه آدرس‌ حافظه، هر پروسه جدولی دارد به نام page-table. این جدول صرفا شماره فریم هر page را به ما می‌دهد. مثلا برنامه می‌خواهد از page شماره ۱۲ داده‌ای را بخواند. سخت‌افزار و سیستم‌عامل باید با استفاده از page-table  فریم متناظر با page شماره ۱۲ را پیدا کنند. بعد داده مورد نظر را از آن فریم بخوانند و در اختیار برنامه دهند. این یعنی برنامه به‌هیچ‌وجه درگیر جزئیات ترجمه و آدرس‌دهی و مخلفات نمی‌شود. و اصلا برای برنامه مهم نیست که این page مال کدام frame است یا در کجا ذخیره شده.شمای کلی یک آدرس منطقی به این شکل است: بخش ابتدایی آدرس شماره page را مشخص می‌کند.همان‌طور که در تصویر واضح است، هر آدرس logical از دو بخش تشکیل می‌شود. بخش ابتدائی که شماره page را مشخص می‌کند و با استفاده از آن می‌توان فریم متناظر با آن page را در page-table پیدا کرد. و همچنین بخش انتهای آن، که بعد از پیدا کردن فریم، نشان‌دهنده خانه dام از فریم است. در واقع ترجمه آدرس منطقی به فیزیکی در ۳ مرحله زیر انجام می‌شود:پیدا کردن شماره page از آدرس منطقی،استفاده از شماره page برای پیدا کردن شماره فریم از طریق page-table،جایگذاری کردن شماره فریم با شماره page در آدرس.حتما متوجه شدید که در مراحل ترجمه، آفست یا همان d تغییری نکرده.نحوه ترجمه آدرس منطقی به فیزیکیچطور paging جلوی شکستگی بیرونی را می‌گیرد؟شکستگی‌بیرونی یا همان external-fragmentation در paging وجود ندارد. دلیل آن‌هم این است که هر بخشی از حافظه فیزیکی می‌تواند به هر حافظه‌ای تخصیص داده شود. نمای بیرونی آدرس‌ها که همان آدرس‌های منطقی هستند، پیوسته هستند. اما از نگاه سخت‌افزار، لزوما حافظه‌ تخصیص داده شده به یک برنامه، پیوسته نیست. تصویر زیر این مفهوم را نمایش می‌دهد:حافظه‌ای که از نگاه برنامه پیوسته‌ است لزوما در حافظه فیزیکی پیوسته نیست.شکستگی-درونی چیست؟این روش در کنار مزیت اصلی خود - یعنی از بین بردن شکستگی بیرونی - یک ایراد مشابه دارد و آن internal-fragmentation یا شکستگی درونی است. این یعنی اگرچه مطمئن هستیم هیچ فریم‌ای از حافظه فیزیکی بلا استفاده نخواهد ماند و می‌توان از تمام فریم‌ها برای تمام پروسه‌ها استفاده کرد اما به دلیل ثابت بودن اندازه فریم‌ها نمی‌توان دقیقا حافظه مورد نیاز برنامه‌ها را تأمین کرد و معمولا باید چیزی بیشتر از حافظه مورد نیاز هر پروسه را به آن پروسه تخصیص دهیم. یعنی چی؟فرض کنید اندازه هر سایز ( و به‌ طبیعتا هر page) ۴۰۹۶ باید باشد. اگر یک پروسه ۱۲۵۰۰ بایت حافظه نیاز داشته باشد برای اجرا شدن، باید ۴ فریم به این پروسه اختصاص دهیم. و می‌دانیم که از بخش زیادی از فریم چهارم استفاده نخواهد شد.12500 = 4096 * 3 + 212همان‌طور که مشخص است، پروسه ما، از ۳ فریم ابتدائی استفاده کامل می‌کند اما از فریم چهارم فقط ۲۱۲ بایت را استفاده می‌کند، و ۳۸۸۴ بایت دیگر از این فریم هدر می‌رود. به این پدیده internal-fragmentation گفته می‌شود. بدترین حالت وقوع internal-fragmentation وقتی است که از یک فریم فقط ۱ بایت استفاده شود. مثلا در این مثال ما که اندازه هر فریم ۴۰۹۶ بایت است، بدترین حالت وقتی است که ۴۰۹۵ بایت استفاده نشود.وقتی پروسه جدیدی ایجاد می‌شود، سیستم‌عامل باید حافظه مورد نیاز آن پروسه را در اختیارش قرار دهد. فرض می‌کنیم که پروسه جدید به n فریم نیاز دارد. سیستم‌عامل در حافظه می‌گردد و سعی می‌کند n فریم از هر جای حافظه که بود پیدا کند. وقتی این n فریم پیدا شد، در حافظه منطقی به ازاء هر فریم یک page ساخته می‌شود و نهایتا یک page-table برای این پروسه ساخته می‌شود که آدرس فیزیکی هر فریم را به آدرس منطقی آن page وصل می‌کند. باید توجه داشت که در حالت ساده، هر پروسه page-table  خودش را دارد.ذخیره page-table هابه ازا هر پروسه ما یک page-table  داریم. از آن‌جایی که page-table ها نسبتا حجیم هستند، نگه‌داری آن‌ها یک چالش مهم است. اولین راهکار برای نگه‌داشتن آن‌ها این است که کل page-table  را داخل حافظه کش پردازنده ذخیره کنیم. بدین شکل، سرعت دسترسی به page-table بسیار زیاد خواهد بود. اما از آن‌جایی حافظه کش محدود است، ما دوست نداریم بخش عمده آن را به page-table  اختصاص دهیم. از طرف دیگر، چون page-table مخصوص هر پروسه است، در مواقعی که پروسه‌ها عوض می‌شوند، هزینه زمانی context-switch بالا خواهد بود. یعنی پردازنده باید کل مقادیر page-table پروسه قدیم را از حافظه کش خود پاک کند و کل page-table حافظه جدید را در حافظه کش خود بارگذاری کند. این‌کار زمان زیادی خواهد برد.راه‌حلی که برای مشکل بالا وجود دارد، این است که یک بخش بسیار کوچک از حافظه کش پردازنده را، به‌عنوان اشاره‌گر به page-table قرار دهیم. مقادیر اصلی page-table داخل حافظه اصلی ذخیره شده‌اند. و با استفاده از اشاره‌گری که در حافظه کش داریم می‌توانیم به آن دسترسی پیدا کنیم. به آن اشاره‌گر اصطلاحا page-table base register یا PTBR گفته می‌شود.راهکار بالا در عمل خیلی کارا نیست. چون دسترسی به حافظه اصلی به نسبت حافظه کش پردازنده بسیار سخت‌تر و کندتر است. برای حل این مشکل، طراحان‌سیستم‌عامل دست به دامن سخت‌افزار شدند.راه‌حل نهایی و استاندارد برای حل این مشکل، داشتن یک حافظه کش جداگونه مخصوص نگه‌داری page-tableها بود. نام این سخت‌افزار translation look-aside buffer یا TLB است. TLB نوعی حافظه key-value هست برای نگه‌داری ساده داده‌های page-table.این راه‌حل نتیجه مشاهدات طراحان سیستم‌عامل بود. این مشاهدات، نشان می‌داد که در غالب موارد، برنامه‌ها به تعداد کمی از page های خود احتیاج دارند. یعنی درصد زیادی از مواقع برنامه‌ها به بخش کوچکی از حافظه خود نیاز دارند. همان‌طور که گفته شد، TLB نوعی حافظه کش است. پس معمولا آخرین page-tableهایی که استفاده شده‌اند را در خود نگه می‌دارد. این بدین معناست که غالبا وقتی یک پروسه جدید ایجاد می‌شود، ابتدا با TLB miss مواجه می‌شود. یعنی داده‌های page-table  داخل TLB ذخیره نشده‌اند. اما در ادامه دیگر احتمالا این اتفاق رخ ندهد. TLB تعداد دسترسی به حافظه اصلی برای page-table را به شدت پایین می‌آورد. اشتراک‌ فریم‌ها یا pageهای اشتراکییکی از مزایایی که paging دارد، استفاده اشتراکی از بعضی از فریم‌های حافظه است. فرض کنید چند برنامه که از کتاب‌خانه اشتراکی X استفاده می‌کنند همزمان در حال اجرا هستند. اگر مطمئن باشیم که استفاده از این کتاب‌خانه‌ها صرفا خواندن است (یعنی داده‌ها تغییری نمی‌کنند) می‌توانیم فریم‌های یکسانی را به چند page در پروسه‌های مختلف نظیر کنیم. تصویر زیر این مطلب را نشان می‌دهد:همان‌طور که تصویر بالا مشخص است، در تصویر بالا ۳ پروسه هم‌زمان از فریم‌های ۱، ۳،۴ و ۶ استفاده می‌کنند. </description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Fri, 22 Oct 2021 13:27:14 +0330</pubDate>
            </item>
                    <item>
                <title>نگاهی بر مدیریت حافظه توسط سیستم‌عامل - تخصیص پیوسته حافظه</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D8%B1-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AD%D8%A7%D9%81%D8%B8%D9%87-%D8%AA%D9%88%D8%B3%D8%B7-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D8%B9%D8%A7%D9%85%D9%84-%D8%AA%D8%AE%D8%B5%DB%8C%D8%B5-%D9%BE%DB%8C%D9%88%D8%B3%D8%AA%D9%87-%D8%AD%D8%A7%D9%81%D8%B8%D9%87-zrji8rziynjv</link>
                <description>در قسمت قبل به طور خلاصه به برخی مفاهیم پایه در مدیریت حافظه توسط سیستم‌عامل پرداختیم. در این بخش در موضوع مدیریت حافظه اندکی بیشتر عمیق می‌شویم و با مفهوم «تخصیص پیوسته حافظه» آشنا می‌شویم.تخصیص پیوسته حافظه چیست؟حافظه کامپیوتر، از تعدادی بایت تشکیل شده که هر کدام آدرس مشخصی دارند. آدرس خانه‌های حافظه از ۰ شروع می‌شود و جلو می‌رود. این یعنی برای دسترسی به یک خانه از حافظه، تنها به یک عدد - آدرس آن خانه از حافظه - نیاز داریم. این مسئله باعث می‌شود نوع تخصیص خانه‌های حافظه مهم باشد. در تخصیص پیوسته حافظه، سیستم‌عامل بلوک‌های مجاور حافظه را به پروسه‌ها تخصیص می‌دهد. در ابتدای امر، کل حافظه دست‌نخورده است. البته منظور از کل حافظه، بخش مربوط به پروسه‌های کاربر است، یعنی احتمالا بخش‌های پایینی حافظه (حافظه، به طور کلی به دو بخش ‌kernel space و user space تقسیم می‌شود، که اولی حافظه متعقل به سیستم‌عامل است و دومی حافظه متعلق به پروسه‌های مربوط به کاربر. بدیهی است که از بدو اجرا سیستم‌عامل، بخش ‌kernel space مورد استفاده قرار می‌گیرد). حالا وقتی یک پروسه از سیستم‌عامل مقدار معینی حافظه درخواست می‌کند، سیستم‌عامل از اولین خانه خالی تا جای مورد نیاز را به طور پیوسته در اختیار این پروسه قرار می‌دهد. وقتی پروسه دومی دوباره از سیستم‌عامل درخواست حافظه کند، سیستم‌عامل از آخرین حافظه اشغال شده توسط پروسه اول، تا جایی که لازم است را در اختیار پروسه جدید قرار می‌دهد. بدین معنا که هیچ حافظه بلااستفاده‌ای بین حافظه تخصیص یافته به پروسه اول و دوم نیست. این دو بخش کاملا در مجاورت یکدیگر قرار دارند. این روند تا جایی پیش‌می‌رود که کل حافظه پر شود. در این حین، ممکن است بعضی از پروسه‌های قبلی که حافظه را اشغال کرده‌اند، کارشان تمام شود و حافظه را آزاد کنند. چالش اصلی استفاده مجدد از این بخش‌های آزاد شده است.اصطلاحا به بخش‌هایی از حافظه که خالی و آزاد هستند (توسط هیچ پروسه‌ای اشغال نشده‌اند) سوراخ یا ‌hole گفته می‌شود. در طول اجرای پروسه‌های مختلف و اتمام کار آن‌ها، سوراخ‌های زیادی در حافظه ایجاد می‌شود. این سوراخ‌ها اندازه‌های متغییر دارند. و این باعث می‌شود که مقدار زیادی حافظه خالی و آزاد باشد. وقتی پروسه جدیدی ایجاد شود، از سیستم‌عامل درخواست حافظه می‌کند. سیستم‌عامل بخش‌های استفاده نشده (همان سوراخ‌ها)  حافظه را بررسی می‌کند، اگر هرکدام به اندازه حافظه مورد نیاز پروسه بود، آن بخش را در اختیار آن پروسه قرار می‌دهد. تصویر زیر تا حدی این مسئله را شفاف می‌کند.پروسه‌های جدید جای پروسه‌های قدیمی را می‌گیرنددر تصویر بالا نشان داده می‌شود که پروسه ۸ به اتمام می‌رسد و یک سوراخ در حافظه ایجاد می‌شود. در مرحله بعد پروسه ۹ وارد حافظه می‌شود و بخشی از فضای استفاده نشده را استفاده می‌کند. در مرحله بعد پروسه ۵ از مدار خارج می‌شود و سوراخ دیگری در حافظه ایجاد می‌شود. اما مشکل اصلی این است که این بخش‌های بلااستفاده از حافظه در کنار یکدیگر نیستند و در کل حافظه پخش هستند. این باعث می‌شود که نتوانیم به طور بهینه از آن‌ها استفاده کنیم. همان‌طور که در تصویر بالا مشخص است، ما در مرحله آخر، ۲ تکه بلااستفاده از حافظه را داریم که در مجاورت یک‌دیگر نیستند. به عبارتی پیوسته نیستند. اگر پروسه جدیدی درخواست حافظه داشته باشد، سیستم‌عامل باید ببیند آیا هر کدام از این بخش‌ها کفاف این پروسه را خواهند  داد یا خیر. ممکن است مجموع این سوراخ‌ها نیاز پروسه جدید را رفع کنند، اما به این دلیل که این بخش‌ها در مجاورت یکدیگر نیستند، نمی‌توانیم از آن‌ها استفاده کنیم.یعنی ممکن است در طول اجرا پروسه‌ها، به جایی برسیم  حجم زیادی از حافظه آزاد است، اما به این دلیل که این بخش‌ها بین پروسه‌های مختلف پخش هستند و یک‌پارچه نیستند، نمی‌توان از آن‌ها استفاده کرد. به اتلاف حافظه آزاد اما غیرقابل استفاده اصطلاحا external-fragmentation گفته می‌شود. بدترین حالت external-fragmentation این است که بین هر دو پروسه، مقداری حافظه آزاد وجود داشته باشد.به عبارتی، در تخصیص پیوسته حافظه، هر پروسه، باید در خانه‌های مجاور حافظه مستقر باشد. این مسئله از جهاتی سرعت پردازش آن پروسه را بالاتر می‌برد، اما از طرف دیگر استفاده بهینه از حافظه یک چالش خواهد بود. وقتی یک پروسه از سیستم‌عامل درخواست حافظه می‌کند، سیستم‌عامل باید بین بخش‌های آزاد حافظه، یک سوراخ (یا بخشی از یک سوراخ) را در اختیار آن پروسه قرار دهد. اینکه سیستم‌عامل کدام بخش را در اختیار پروسه قرار می‌دهد، استراتژی سیستم‌عامل است. به طور کلی سه نوع مسیر برای تخصیص حافظه به پروسه‌ها وجود دارد:first-fit: یعنی اولین بخش خالی از حافظه که اندازه‌اش مساوی یا بزرگ‌تر از مقدار حافظه مورد نیاز باشد را انتخاب کند.best-fit: یعنی آن بخشی از حافظه را به پروسه تخصیص بدهیم، که اندازه‌اش بیشتر از همه به مقدار حافظه مورد نیاز نزدیک باشد.worst-fit: یعنی بزرگ‌ترین بخش حافظه که را به پروسه اختصاص دهیم. البته درصورتی که بزرگ‌ترین بخش خالی، کفاف نیاز پروسه را بدهد.طبیعی است که مورد آخر بهینه نیست. اما بین دو مورد best-fit و first-fit کاملا مشخص نیست کدام بهتر هستند. اگرچه best-fit استفاده بهینه‌تری از حافظه می‌کند، اما زمان بیشتری طول می‌کشد تا سیستم‌عامل بهترین گزینه را انتخاب کند. برعکس، در حالت first-fit سیستم‌عامل اولین بخش مناسب را انتخاب می‌کند و این زمان خیلی کمتری خواهد برد.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Sun, 03 Oct 2021 07:57:54 +0330</pubDate>
            </item>
                    <item>
                <title>نگاهی بر مدیریت حافظه توسط سیستم‌عامل - مفاهیم اولیه</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D8%B1-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AD%D8%A7%D9%81%D8%B8%D9%87-%D8%AA%D9%88%D8%B3%D8%B7-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85-%D8%A7%D9%88%D9%84%DB%8C%D9%87-akd5ixy9q6va</link>
                <description>در این مطلب سعی می‌کنم صرفا مفاهیم اولیه‌ای که برای مدیریت حافظه توسط سیستم‌عامل بکار گرفته می‌شود را در حد سواد خودم تشریح کنم. در بخش‌های بعدی احتمالا بیشتر به تکنیک‌های مختلف مدیریت حافظه می‌پردازم.حافظه‌های داخلی پردازنده، و حافظه اصلی خود کامپیوتر، تنها ظرفیت‌هایی هستند که پردازنده مستقیما دسترسی به آن‌ها دارد. پردازنده برای اجرا هر دستور (instruction) نیاز به داده‌هایی دارد (مثلا ورودی‌های آن instruction) و همه این این داده‌ها به علاوه خود instruction باید یا در حافظه اصلی و یا در حافظه‌های داخلی خود پردازنده قرار داشته باشند. پردازنده دسترسی مستقیم به دیسک ندارد و این قید ما را ملزم می‌کند که قبل از اجرا هر دستور، تمامی داده‌های مرتبط و مورد نیاز آن را در حافظه بارگذاری کنیم و از آن‌جایی که حافظه محدود است، و داده‌ها زیاد، مدیریت حافظه به بخشی حیاتی از طراحی سیستم‌عامل تبدیل می‌شود.توضیح مختصری بر انواع حافظه‌هاحافظه‌هایی که ما با آن‌ها سر و کار داریم از چند نوع مختلف می‌توانند باشد. معمولا منظور ما از حافظه، حافظه volatile است. یعنی حافظه‌ای که فقط هنگام اتصال برق به سیستم اطلاعات را در خود ذخیره می‌کند، و بعد از قطعی برق، تضمینی برای بقای داده‌ها وجود ندارد. دو مثال اصلی از این نوع حافظه‌های volatile رجیسترهای پردازنده و RAM هستند. حافظه‌های non-volatile هم حافظه‌هایی هستند که بعد از قطعی برق و خاموشی سیستم، داده‌ها را برای مدت طولانی (حتی چند ده سال) در خود نگه‌داری می‌کند. تصویر زیر حرف‌های خوبی برای گفتن دارد:تصویر از کتاب Operating System Conceptsتعامل پردازنده با حافظه‌هاپردازنده تنها به ۳ حافظه بالایی در تصویر بالا دسترسی مستقیم دارد. یعنی حافظه‌های register، cache و main memory. که دو مورد اول حافظه‌های داخلی خود پردازنده هستند. حافظه‌ register، که نزدیک‌ترین حافظه به خود پردازنده است، کمترین ظرفیت را دارد، چیزی در حدود ۵۱۲ بایت، یا کمتر. داده‌های مورد نیاز برای اجرا هر دستورالعمل، الزاما باید در این حافظه بارگذاری شده باشند قبل از شروع اجرا. پردازنده برای دسترسی به داده‌های داخل registerهای خود، زمان بسیار کمی را صرف می‌کند. در حد یک یا دو CPU clock.  اما برای دسترسی به داده‌های داخل حافظه اصلی، زمان بسیار بیشتری را باید صرف کند، که این زمان ممکن است به چند صد CPU clock نیز برسد. و از آنجایی که پردازنده مکررا نیاز دارد به داده‌های داخل حافظه اصلی دسترسی داشته باشد، سرعت اجرا برنامه‌ها به طرز قابل توجهی افت می‌کند. راه‌حل این مشکل، حافظه میانی cache بود. این حافظه داخل خود پردازنده تعبیه شده و بسیار به هسته پردازنده نزدیک است. این قرابت زیاد، موجب می‌شود که سرعت آن به طرز چشم‌گیری افزایش پیدا کند. نمودار زیر این مسئله را به خوبی ترسیم می‌کند:نمودار از کتاب high performance pythonهمان‌طور که می‌بینید سرعت خواندن داده از حافظه‌های کش، به چند هزار میلیارد بیت بر ثانیه می‌رسد در حالی که این سرعت برای حافظه RAM چند ده میلیارد بیت بر ثانیه است. وجود حافظه کش باعث می‌شود پردازنده در غالب موارد، نیاز نداشته باشد داده‌های مورد نظر خود را مستقیما از حافظه بردارد. و این بهبود قابل‌توجهی به سرعت پردازش می‌دهد.logical address و physical addressدو نوع آدرس‌دهی در دنیای سیستم‌عامل داریم. نوع اول که بدیهی‌ترین نوع آن است، آدرس‌دهی فیزیکی است. یعنی عینا آدرس آن خانه از حافظه که داده مورد نظر داخل آن قرار دارد را داشته باشیم. مثلا وقتی می‌گوییم آدرس فیزیکی این داده 0x412f51ِ است، یعنی دقیقا در خانه 0x412f51ام از حافظه این داده ذخیره شده است. اما آیا برنامه‌ها به این آدرس دسترسی دارند؟ به دلایلی بهتر است که برنامه‌ها مستقیما به آدرس فیزیکی سیستم دسترسی نداشته باشند. از طرفی مجرد کردن (abstraction) برنامه‌ها از دنگ و فنگ‌های سخت‌افزاری و مشکلات سطح‌پایین یک مزیت محسوب می‌شود، از طرف دیگر دادن آدرس فیزیکی، ناخواسته داده‌های از سیستم را به برنامه می‌دهد که لزومی ندارد بداند. مثلا حداقل ظرفیت حافظه را از آدرس فیزیکی می‌توان تخمین زد. به علاوه دادن آدرس فیزیکی به برنامه‌ها، دسترسی آن‌ها را به داده‌های دیگری که در بخش‌های دیگر حافظه ذخیره شده‌اند هموارتر می‌کند. لذا آدرس منطقی یا logical address به داد ما می‌رسد.این نوع آدرس، توسط خود پردازنده تولید شده و در واقعیت وجود ندارد. مثلا وقتی پردازنده حافظه 0x100a را به یک برنامه می‌دهد، بدین معنا نیست که واقعا خانه 0x100a ام از حافظه را در اختیار برنامه گذاشته. این آدرس به عبارتی یک آدرس مجازی است که توسط سخت‌افزاری به نام MMU  (memory management unit) تبدیل به آدرس فیزیکی می‌شود. این‌کار تا حدی باعث می‌شود که برنامه‌ها از یک‌دیگر در بعضی از سطوح ایزوله‌تر شوند. به علاوه، حافظه منطقی، در مدیریت حافظه وقتی که حافظه درخواستی از سمت برنامه‌ها بیشتر از حافظه موجود کامپیوتر است شدیدا مفید واقع می‌شود.base register و limit registerبرای مدیریت حافظه، هر پروسه، ۲ رجیستر مهم دارد:base register: که اشاره دارد به اولین آدرسی که برنامه مجاز به استفاده از آن است.limit register: که اشاره دارد به مقدار حافظه‌ای که بعد از حافظه base برنامه مجاز به استفاده است.مثلا وقتی رجیستر بِیس یک برنامه ۵۲۰ باشد، و رجیستر limit آن ۸۰ باشد، یعنی برنامه مجاز به استفاده حافظه از خانه ۵۲۰ تا ۵۲۰+۸۰ است. یعنی از ۵۲۰ تا ۶۰۰ محدوده مجاز برای استفاده توسط این برنامه است. در تصویر زیر رابطه این دو رجیستر را می‌توان مشاهده کرد:اگر حافظه درخواستی مجاز نباشد، سیستم‌عامل دسترسی به آن حافظه را به برنامه نمی‌دهد.Dynamic loadingدر ابتدا گفته شد که برای اجرا هر برنامه، لازم هست که کل آن پروسه در حافظه بارگذاری شود و سپس اجرا پروسه شروع شود. این‌کار در پیاده‌سازی نسبتا راحت است اما ممکن است حجم زیادی از حافظه بی‌مورد اشغال شود. برای مثال فرض کنید، برنامه ویرایش متنی را اجرا می‌کنید. این برنامه احتمالا قابلیت‌های فراوانی دارد و شما در هر لحظه از همه آن‌ها استفاده نمی‌کنید. به همین علت شاید بیهوده باشد که همه برنامه در حافظه ذخیره شوند. احتمالا بهتر است که بخشی از برنامه که در لحظه اجرا استفاده می‌شود در حافظه ذخیره شود و باقی برنامه در دیسک بماند. هر موقع نیاز شد از آن‌ها استفاده کنیم، آن بخش از برنامه را سریعا از دیسک به حافظه منتقل می‌کنیم. البته که واضح است این کار سرعت پردازش را تا حدی کند می‌کند اما استفاده از حافظه را به مراتب بهینه‌تر می‌کند.در مطالب بعدی احتمالا از تکنیک‌های مختلف مدیریت حافظه مثل paging و حافظه مجازی صحبت کنیم.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Fri, 24 Sep 2021 12:28:16 +0330</pubDate>
            </item>
                    <item>
                <title>کدهای هافمن چه هستند؟</title>
                <link>https://virgool.io/@riahiamirreza79/%DA%A9%D8%AF%D9%87%D8%A7%DB%8C-%D9%87%D8%A7%D9%81%D9%85%D9%86-%DA%86%D9%87-%D9%87%D8%B3%D8%AA%D9%86%D8%AF-pqe02l5jhgn0</link>
                <description>کدهای هافمن نوعی کد پیشوندی هستند که برای انتقال بهینه اطلاعات استفاده می‌شوند. منظور از انتقال بهینه اطلاعات استفاده از کمترین bit ممکن برای منتقل کردن اطلاعات مورد نظر است. به بیان دیگر، الگوریتم هافمن برای تبدیل داده‌ها به کدهای هافمن، نوعی الگوریتم فشرده‌سازی است. فشرده‌سازی اطلاعات، بخشی از نظریه اطلاعات است که حدودا در دهه ۱۹۴۰ میلادی توسط شانون پایه‌گذاری شد.کدهای هافمن مبتنی بر دو مشاهده بودنددر یک کد بهینه، علائمی که بیشتر تکرار می‌شوند، کوتاه‌تر از (تعداد bit کمتری دارند) علائمی که کمتر تکرار می‌شوند.در یک کد بهینه، دو علامتی که کمتر از همه تکرار می‌شوند، طول یکسانی دارند.مشاهده اول بنظر منطقی است. فرض کنید می‌خواهیم کلمه Hello  را کد کنیم. اگر کد ما به نحو زیر باشد قاعدتا خیلی جالب نیست:H  --&gt; 11
e  --&gt; 10
l  --&gt; 01
o  --&gt; 00اگر بخواهیم کلمه Hello  را با کد بالا کدگذاری کنیم خروجی کار رشته زیر می‌شود:1110010100طول رشته بالا ۱۰ بیت است. اما وقتی می‌دانیم حرف l، در کلمه ۲ بار تکرار شده، منطقی‌تر این است که این حرف طول کمتری داشته باشد. پس سعی می‌کنیم کد را تغییر دهیم تا اندکی بهینه‌تر شود. H  --&gt; 01
e  --&gt; 00
l  --&gt; 1
o  --&gt; 011کد شده کلمه Hello  بر اساس کد بالا رشته زیر می‌شود:010011011که طول این کد ۹ بیت است. پس اگر علامتی که بیشتر تکرار می‌شود، طولانی‌تر از علامتی باشد که کمتر تکرار می‌شود، کد ما بهینه نیست. چون با جابجا کردن این دو علامت، کد ما بهینه‌تر می‌شود. لذا برای بهینه بودن کد، این قاعده ضروری است.درمورد مشاهده دوم، باید اندکی بیشتر دست و پا زد تا واضح‌تر شود. فرض کنیم کدی بهینه داریم. ۲ علامتی که کمترین تکرار را دارند را در نظر بگیریم a و b. فرض می‌کنیم این دو علامت هم‌اندازه نیستند. وقتی هم‌اندازه نیستند پس قاعدتا یکی از دیگری k بیت طولانی‌تر است. فرض می‌کنیم طول a بیشتر است.length (a) = length (b) + kحالا از آنجایی که می‌دانیم این کدها پیشوندی هستند (یعنی هیچ‌کدام پیشوند دیگری نیستند) می‌توانیم k بیت اضافه علامت a را حذف کنیم، و نگران متمایز بودن آن با باقی علائم نشویم. پس کد جدیدی می‌توانیم داشته باشیم که تعداد بیت‌های تشکیل دهنده علامت a کمتر است. لذا کد قبلی بهینه نبود.یک قاعده دیگر را هم باید لحاظ کنیم در مورد کدهای فاهمندو علامت با کمترین تکرار (مثل a و b) در مثال بالا، باید فقط در بیت آخر خود متمایز باشند. یعنی اگر m را رشته بیت‌های سازنده a بدانیم. و n را رشته بیت‌های سازنده b بدانیم، داریم: s + `1` = m
 s + `0` = nیعنی s رشته بیتی بود که فقط با افزودن یک بیت دیگر به آن، یا به m تبدیل می‌شد یا به n. این قاعده، ۲ مشاهده ابتدائی ما را نقض نمی‌کند، لذا مشکلی نیست.خب حالا چه کنیم؟ابتدا فرض می‌کنیم می‌خواهیم رشته &quot;Hello mello&quot; را با الگوریتم هافمن، کد کنیم. برای شروع باید جدولی  داشته باشیم به شکل زیر:letter   |  probability | code-word
_______________________________
`l`      |  0.4         | C(l)
`o`      |  0.2         | C(o)
`e`      |  0.2         | C(e)
`H`      |  0.1         | C(H)
`m`      |  0.1         | C(m)    طبق دو مشاهده‌ای که بالاتر گفته شد، می‌دانیم که طول C(H) و C(m) برابر است. چون هر دو کم تکرار ترین حروف هستند. و طبق فرض میدانیم که این دو کد، فقط در بیت آخر باهم تفاوت دارند. پس داریم:C(H) = a + `0`
C(m) = a + `1`حالا برای حذف کردن یکی از این حروف،  دو حرف H و  m را ترکیب می‌کنیم، و جای آن، بخش مشترک این دو حرف، یعنی a را، قرار می‌دهیم. با این تغییر، جدول ما در مرحله بعد به صورت زیر می‌شود:letter   |  probability | code-word
_______________________________
`l`      |  0.4         | C(l)
`o`      |  0.2         | C(o)
`e`      |  0.2         | C(e)
 X       |  0.2         | a همان‌طور که مشاهده می‌کنید، احتمال وجود حرف X (حرفی که در واقع وجود ندارد، ترکیبی است از حروف H و m) ۰.۲ است، یعنی مجموع احتمال حروف H و m. دقیقا همان کار را برای جدول دوم تکرار می‌کنیم. می‌دانیم که ۲ حرف آخر با کمترین احتمال، طول یکسانی دارند و تنها تفاوتشان، آخرین بیت است. پس دوباره خواهیم داشت:a = b + `1`
C(e) = b + `0`در اینجا b بخش مشترک دو رشته بیت a و C(e) است. بر اساس دو تساوی بالا، می‌توانیم برسیم به:C(H) = a + `0` = b + `10`
C(m) = a + `1` =  b + `11`دیدیم که الان یک مرحله پیشرفت کردیم. از کدهای کاراکترهای H و m الان ۲ بیت داریم. حالا دوباره همان مرحله را تکرار می‌کنیم. ترکیب دو عنصر پایینی با یک‌دیگر.letter   |  probability | code-word
_______________________________
`l`      |  0.4         | C(l)  
 Y       |  0.4         |  b 
`o`      |  0.2         | C(o)و با توجه به یکسان بودن طول دو عنصر آخر داریم:b = c + `1`
C(o) = c + `0`که در وهله بعد:C(H) = b + `10` = c + `110`
C(m) = b + `11` = c + `111`
C(e) = b + `0`  = c + `10`با تکرار کردن همین الگو، در مرحله بعد جدول به شکل زیر خواهد شد:letter   |  probability | code-word
_______________________________
 Z       |  0.6         | c
`l`      |  0.4         | C(l)  که در مرحله آخر داریم:c = d + `1`
C(l) = d + `0` که خب نتیجه میگیریم:C(H) = c + `110` =  d + `1110`
C(m) = c + `111` = d + `1111`
C(e) = c + `10` = d + `110`
C(o) = c + `0` =  d + `10`
C(l) = d + `0`حالا همه حروف را بر حسب d داریم. فرض می‌کنیم d رشته‌ای تهی یا خالی است. در این صورت کد ما به صورت زیر خواهد شد:letter   |  probability | code-word
_______________________________
`l`      |  0.4         | 0
`o`      |  0.2         | 10
`e`      |  0.2         | 110
`H`      |  0.1         | 1110
`m`      |  0.1         | 1111   طبق قاعده دو حرف با کمترین احتمال، طول یکسان دارند و تنها بیت آخرشان متمایز است. همچنین حروف با احتمال بیشتر، طول کمتری دارند. به علاوه این کد، کد پیشوندی نیز هست. یعنی هیچ کلمه‌ای، پیشوند کلمه دیگر نیست. حالا می‌توانیم &quot;Hello mello&quot; را کدگذاری کنیم:1110,110,0,0,10,1111,110,0,0,10که خب چون کد پیشوندی است، نیازی به حروف جدا کننده ندارد لذا داریم:1110110001011111100010۳ نکته در انتها لازم به ذکر است.اول اینکه خودم متوجه هستم که کاراکتر فاصله را در فشرده سازی لحاظ نکردم. برای سادگی بود :)دوم اینکه حروف a، b، c و d هیچ‌کدام حرفی از داده‌ای که باید منتقل می‌شد نبودند. این‌ها صرفا علامتی برای نشان دادن رشته بیت‌های مشترک بودند.سوم هم اینکه خودم می‌دانم به شدت افتضاح و ناقص این الگوریتم را توضیح دادم. در واقع اصلا توضیح داده نشد، صرفا یک مثال از آن را حل کردیم. برای اطلاعات بیشتر شما را به فصل ۳ از کتاب Introduction to data compression ارجاع می‌دهم. خیلی کامل خوب همه چیز توضیح داده شده. وقت خودتان را با خواندن دوباره مهملاتی که اینجا نوشتم هدر ندهید!</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Fri, 17 Sep 2021 23:28:06 +0430</pubDate>
            </item>
                    <item>
                <title>ایندکس کردن خوشه‌ای یا غیر خوشه‌ای؟</title>
                <link>https://virgool.io/@riahiamirreza79/%D8%A7%DB%8C%D9%86%D8%AF%DA%A9%D8%B3-%DA%A9%D8%B1%D8%AF%D9%86-%D8%AE%D9%88%D8%B4%D9%87-%D8%A7%DB%8C-%DB%8C%D8%A7-%D8%BA%DB%8C%D8%B1-%D8%AE%D9%88%D8%B4%D9%87-%D8%A7%DB%8C-ahghveblss6h</link>
                <description>داده‌ها در دیتابیس ذخیره می‌شوند. اما چگونه پیدا می‌شوند؟ یک مثال خیلی معروفی که همیشه برای توضیح بعضی مفاهیم پایگاه داده استفاده می‌شود، مثال دفترچه تلفن است. فرض کنید دفتری دارید که شماره هر نفر را با نامش در آن می‌نویسید. ساده‌ترین راه وارد کردن شماره افراد  در این دفترچه چیست؟ به ترتیب هر نفری که اضافه می‌شود را به آخر لیست اضافه کنیم. در این حالت، اضافه کردن هر عضو جدید به دفترچه از مرتبه  O(1) زمان لازم دارد. یعنی مهم نیست قبلا چند نفر وارد دفترچه شده‌اند، اگر می‌خواهی عضو جدیدی اضافه کنی، باید یک زمان ثابت صرف انجام این‌کار کنی.طبیعی است که پیدا کردن شماره افراد در این دفترچه کار راحتی نخواهد بود اگر تعداد شماره‌ها زیاد باشد. در تعداد پایین، به راحتی می‌توان با بررسی تک‌تک خطوط دفترچه، شماره مورد نظر را پیدا کرد. به این نوع جستجو sequential scanning گفته می‌شود که در تعداد پایین خیلی خوب جواب می‌دهد. اما وقتی یک میلیون شماره داشته باشیم باید چه ‌کنیم؟ پیدا کردن شماره افراد در این دفترچه تلفن، برعکس اضافه کردنش، کار دشواری است که از مرتبه O(n) است. یعنی زمان مورد نیاز برای پیدا کردن هر شماره، رابطه خطی دارد با تعداد شماره‌های داخل دفترچه. برای بهبود بخشیدن به وضعیت دفترچه، باید اندکی زحمت بیشتری هنگام افزودن یک شماره به دفترچه بکشیم. در این صورت ممکن است موقع خواندن کار ساده‌تر شود. به این‌کار ایندکس کردن می‌گویند. به مرتب کردن یا دسته‌بندی کردن داده‌های پایگاه‌داده، به نحوی که پیدا کردن هر داده ساده‌تر شود، ایندکس کردن گفته می‌شود. حالا ساده‌ترین راه ممکن برای ایندکس کردن داده‌ها چیست؟ایندکس کردن خوشه‌ای یا clustered indexingساده‌ترین راه برای تسهیل جستجو در دفترچه تلفن (ساده‌ترین راهی که به ذهن من می‌رسد) این است که افراد را به ترتیب حروف الفبا وارد دفترچه کنیم. واضح است که نوشتن عضو جدید در دفترچه سخت‌تر می‌شود. اما در عوض پیدا کردن یک شماره در کل دفترچه از مرتبه O(log n) زمان خواهد برد. به عبارتی از این به بعد می‌توانیم جستجوی باینری انجام بدهیم برای پیدا کردن عضو جدید.داده‌ها به ترتیب مرتب می‌شونداین راه نسبتا خوب بود نه؟ اما طبیعتا معایبی هم دارد. در این مثال شاید کمتر معایبش پیدا باشد. برای اینکه بهتر این نوع از ایندکس کردن را درک کنیم بهتر است مثال بهتری بزنم. فرض کنید پایگاه‌داده‌ای از اطلاعات دانش‌آموزان یک مدرسه داریم. هر دانش‌آموز اطلاعات معدل، سن، مقطع تحصیلی و نام را دارد. خب حالا برای وارد کردن این دانش‌آموزان به پایگاه‌داده همه دانش‌آموزان را براساس نامشان مرتب می‌کنیم. این‌طوری اطلاعات هر دانش‌آموز را به سرعت می‌توانیم استخراج کنیم. اما اگر خواستیم شاگرد اول را پیدا کنیم باید چه کنیم؟ احتمالا کاری که باید کرد بررسی معدل تک‌تک دانش‌آموزان است. چرا؟ چون دانش‌آموزان را براساس معدل مرتب نکردیم، فقط براساس نام مرتب کردیم. اما آیا می‌توانیم دانش‌آموزان را هم بر اساس معدل و هم بر اساس نام مرتب کنیم؟ شاید بشود اما کار سختی است. چون احتمالا باید دو تا جدول بزرگ داشته باشیم. در هر دو جدول داده‌های یکسانی داشته باشیم. در جدول اول همه دانش‌آموزان بر اساس معدل و در جدول دوم همه بر اساس نام مرتب شده‌اند. حجم خیلی زیادی از اطلاعات دوباره ذخیره می‌شوند. و این خیلی جالب نیست! چه باید کرد؟ایندکس کردن غیرخوشه‌ای یا non-clustered indexingدر ایندکس کردن خوشه‌ای، عینا خود داده‌ها در حافظه مرتب کنار یکدیگر چیده می‌شدند. بدیهی است که نمی‌شود یک سری از داده‌ها را به دو صورت مختلف مرتب کرد. یا باید دانش‌آموزان بر اساس معدل مرتب شوند یا نام. این محدودیت در ایندکس کردن غیرخوشه‌ای رفع شده. روشی که در این نوع از ایندکس کردن استفاده می‌شود این است که جدول جدایی تعبیه می‌شود که در آن هر سطر شامل ۲ عنصر است. یک عنصر، عنصری است که قرار است با آن داده‌ها را مرتب کنیم، و دیگری آدرس حافظه‌ای که آن داده در حافظه ذخیره شده. یعنی چه؟ مثلا فرض کنید می‌خواهیم دانش‌آموزان را هم بر اساس معدل و هم براساس نام مرتب کنیم. علاوه بر جدولی که خود دانش‌آموزان در آن ذخیره شده‌اند، ۲ جدول دیگر خواهیم داشت. در یک جدول، نام دانش‌آموزان به ترتیب الفبا مرتب شده و جلوی هر نام، آدرس حافظه‌ای که اطلاعات آن دانش‌آموز در آن ذخیره شده موجود است. یعنی  شما در این جدول می‌گردی و دانش‌آموز با نام سینا را پیدا می‌کنی. حالا با استفاده از آدرسی که جلوی نام هست به اطلاعات سینا دسترسی پیدا می‌کنی. همین اتفاق درمورد جدول مربوط به معدل هم رخ می‌دهد. جدولی داریم که معدل‌ها مرتب شده، و جلوی هر معدل آدرس حافظه مربوط به دانش‌آموز ذخیره شده.همان‌طور که در تصویر بالا نظره می‌کنید، لزوما داده‌ها به ترتیب داخل حافظه نوشته نشده‌اند. داده‌ها می‌توانند به هر ترتیبی در حافظه ذخیره می‌شوند اما چون حافظه داده‌ها در یک جدول مجزا وجود دارد، می‌توانیم به داده‌ها به صورت مرتب دسترسی داشته باشیم.یکی از معایب این روش این است که دسترسی به هر داده، ۲ مرحله است. ابتدا باید داده در جدول مرتب شده پیدا شود و سپس با استفاده از آدرس، دسترسی به داده اصلی ایجاد شود. اما در ایندکس کردن خوشه‌ای دسترسی کاملا مستقیم بود.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Sat, 04 Sep 2021 23:44:16 +0430</pubDate>
            </item>
                    <item>
                <title>prefix code چیست؟</title>
                <link>https://virgool.io/@riahiamirreza79/prefix-code-%DA%86%DB%8C%D8%B3%D8%AA-rx7j08bfsjik</link>
                <description>کد پیشوندی نوعی کد است که در آن هیچ کلمه‌ای، پیشوند کلمه دیگری نباشد. اما این یعنی چه؟کدگذاری چیست؟چیز خاصی نیست، صرفا یعنی تبدیل یک الفبا به الفایی دیگر. این الفبا لزوما از حروف تشکیل نشده‌اند. می‌توانند بایت یا کلمه باشند. تعریف دقیق‌تر را از قول ویکی‌پدیا نقل می‌کنم:کُد (به انگلیسی: Code) دستورالعمل تبدیل اطلاعات از یک قالب به قالبی دیگر است. به فرایند انجام این کار کدگذاری (Encoding) و عکس این عمل کدبرداری (Decoding) گفته می‌شود. کدگذاری عبارت است از تبدیل اسم یا یک موضوع به یک علامت قراردادی. این علامت می‌تواند به صورت شماره یا حرف انتخاب شده باشد. کد به منزلۀ علامت اختصاری طبقه‌بندی نیز محسوب می‌شود.مثال‌های ساده‌ای می‌توان از کد نشان داد. مثلا فرض کنید هر حرف از حروف الفبا را به شماره ردیف آن حرف در حروف الفبا نظیر کنیم. یعنی: خروجی کدگذاری کلمه سلام بر اساس این قاعده می‌شود:{15,27,1,28}یک مثال پرکاربردتر کد، کد مورس است. که جدول آن به شکل زیر است:حالا کد پیشوندی چیست؟به کدی که هیچ‌کدام از حروفش، پیشوند حرف دیگرش نباشد، کد پیشوندی گفته می‌شوند. مثال:{1,2,3,4,5}آیا در این ۵ حرف، هیچکدام پیشوند دیگری هست؟ خیر! پس این حروف قاعده را رعایت کردند. اما واضح است که این مثال خیلی راهگشا نیست. باید مثال بهتری زد:{1,11,12,2,3}آیا این  این ۵ کلمه، پیشوند یکدیگر هستند؟ بله! حرف «۱» پیشوند «۱۱» و «۱۲» است. یعنی اولین کاراکتر «۱۲» می‌شود «۱».  پس قاعده را رعایت نمی‌کند.بدیهی است که برای کلمه‌های تک حرفی همیشه این قاعده بر قرار است. چون هیچ حرفی پیشوند حرف دیگری نیست. اما همان‌طور که در مثال بالا دیدید، وقتی حروف چند حرفی می‌شوند ممکن است این قاعده برقرار نباشد. مثال زیر با کلمه‌های چند حرفی است که قاعده را رعایت کرده:{11,41,2,42,34}هیچ‌کدام از کلمات بالا پیشوند دیگری نیستند.خب که چه؟این مسئله وقتی اهمیت پیدا می‌کند که ما می‌خواهیم داده‌ای را منتقل کنیم. در واقع وقتی می‌خواهیم رشته‌ای از اطلاعات را به وسیله این کلمات منتقل کنیم. فرض کنید کد ما از این قاعده پیروی نکنند. مثلا همان کد که در مثال دوم دیدیم را در نظر بگیرید:{1,11,12,2,3}فرض کنید بخواهیم رشته‌ای از اطلاعات را با استفاده از این کلمات بسازیم و منتقل کنیم، این رشته فرضا رشته زیر است:11-12-2-3-1واضح است که انتقال اطلاعات به شکلی که بالا نشان دادیم به صرفه نیست. چون به ازا هر کلمه، باید یک حرف جدا کننده استفاده کنیم. و این یعنی حجم داده‌ای که باید منتقل شود خیلی افزایش پیدا می‌کند. پس سعی می‌کنیم بدون حرف جداکننده رشته را منتقل کنیم. خروجی چنین خواهد شد:1112231حال فرض کنید گیرنده پیام این پیام را دریافت می‌کند. چطور باید این رشته را به کلمات سازنده‌اش تجزیه کند؟ با توجه به کلماتی که داریم، چندین حالت ممکن است:1-1-1-2-2-3-1
1-11-2-2-3-1
1-1-12-2-3-1
11-12-2-3-1همانطور که نظاره می‌کنید، تا الان توانستیم ۴ حالت مختلف این رشته را تجزیه کنیم و فقط حالت آخری چیزی بود که مدنظر فرستنده است. ممکن است حالت‌های دیگری‌هم باشد، اما مهم نیست. مهم این بود که بجز حالت صحیح، حالت‌های اشتباه دیگری‌هم برای تفسیر ممکن هستند. پس مشاهده کردیم که بدون استفاده از حروف جداکننده نمی‌توان داده را منتقل کرد طوری که گیرنده دقیقا به همان چیزی که مدنظر فرستنده است برسد. همچنین استفاده از حروف جداکننده به ازا هر کلمه به شدت حجم داده نهایی را بالا می‌برد و به صرفه نیست. به طور مثال در حالت اول (با حروف جداکننده) رشته ما ۱۱ حرفی است. اما بدون این حروف، رشته ما ۷ حرفی است. این اختلاف، در حجم زیاد داده، بیشتر بروز پیدا می‌کند.چه خاکی؟یک راه‌حل اینجا استفاده از کد از نوع پیشوندی است. کد‌هایی که این قاعده را رعایت می‌کنند، از این خطا مصونیت دارند. به بیان دیگر، ممکن نیست هیچ رشته‌ای از کلماتی که از این قاعده پیروی می‌کنند را به دو طریق تفسیر کرد. و این یعنی می‌توانیم کلمات را بدون حروف جداکننده ارسال کنیم. بیایید همین کار را با سومین مثالی که زدیم تکرار کنیم:{11,41,2,42,34}حال رشته‌ای از این کلمات می‌سازیم، مثلا:414223441می‌توان مطمئن بود تنها راه تجزیه این رشته به کلمات سازنده‌اش، به شیوه زیر است:41-42-2-34-41البته بدیهی است که من اثبات نکردم تنها راه تجزیه این رشته همین حالت بالاست. اما با اندکی دست به قلم بردن و کاغذ سیاه کردن می‌توانید خودتان اثبات کنید که تنها راه تجزیه همین است. به علاوه، اگر حجم بیشتری کاغذ سیاه کنید می‌توانید این قاعده را برای تمام کدهای پیشوندی اثبات کنید.این نوع کد را کد پیشوندی یا prefix code می‌نامند. البته که ترجمه فارسی‌اش را مطمئن نیستم.در این  لینک‌ هم  همین مطلب خیلی ساده و سر راست توضیح داده شده.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Fri, 27 Aug 2021 14:39:17 +0430</pubDate>
            </item>
                    <item>
                <title>آیا دو به علاوه دو همیشه می‌شود چهار؟</title>
                <link>https://virgool.io/@riahiamirreza79/%D8%A2%DB%8C%D8%A7-%D8%AF%D9%88-%D8%A8%D9%87-%D8%B9%D9%84%D8%A7%D9%88%D9%87-%D8%AF%D9%88-%D9%87%D9%85%DB%8C%D8%B4%D9%87-%D9%85%DB%8C-%D8%B4%D9%88%D8%AF-%DA%86%D9%87%D8%A7%D8%B1-n3zgrlzlqoju</link>
                <description>بدیهی‌ترین چیزی که از یک برنامه کامپیوتر می‌توان انتظار داشت انجام صحیح عملیات‌ جبری ساده مثل جمع و تفریق است. البته استثناهایی که برای این قضیه وجود دارد را احتمالا خودتان دیده‌اید. مثلا در پایتون داریم:&gt;&gt;&gt;0.1 + 0.2 == 0.3
False
&gt;&gt;&gt;print(0.1 + 0.2)
0.30000000000000004دلیل بروز چنین اشتباه محاسباتی واضحی  ذخیره دو-دویی اعداد است. به‌طور خلاصه شما هیچ وقت نمی‌توانید  عدد ۰.۱ را به طور دو-دویی (باینری) با ارقام متناهی نمایش دهید. وقتی نمی‌توانید با ارقام متناهی نمایش دهید پس باید با ارقام نامتناهی نمایش داد، و طبیعتا این امکان‌پذیر نیست. پس برای ذخیره و استفاده از این عدد باید از یک جایی به بعد بیخیال ارقامش شوید (مثلا بعد از ۲۰ رقم) و این یعنی خطا. یعنی عددی که ذخیره شده دقیقا ۰.۱ نیست. توضیحات مفصل‌تر و لینک‌های بیشتر برای توضیحات مفصل‌تر در اینجا موجود است.اما این مسئله ما نیست. در حال حاضر صحبت درباره خطاهای محاسباتی بزرگ‌تر است. آیا ممکن است در پایتون ۲ به‌علاوه ۲ مساوی با ۴ نشود؟متاسفانه یا خوشبختانه بله. اما به‌طور طبیعی این اتفاق نمی‌افتد. ولی بعد از یک انگولک ساده، واقعا می‌توانید عبارت زیر را وارد shell پایتون کنید و خروجی زیر را تحویل بگیرید:&gt;&gt;&gt;2 + 2
2اما قبل از آن لازم است توضیحی درخصوص پایتون بدهم. البته که این توضیح خیلی ساده شده‌ایست در حد سواد خودم. PyObject چیست؟در پیاده‌سازی CPython، استراکچری تعریف شده به نام PyObject. تمامی چیزهایی که در پایتون می‌بینید نمونه‌هایی از این Pyobject هستند. منظور از تمام چیزها، واقعا تمام چیزهاست! از اعداد و رشته‌ها گرفته تا توابع و کلاس‌ها و حتی ماژول‌ها. این آبجکت‌ها هرکدام باید یک عدد داشته باشند به نام id. این id فی‌الواقع عددی است، ثابت و یکتا. هیچ دو آبجکتی id یکسان نخواهند داشت. به‌طور خاص در پیاده‌سازی CPython، برای id هر آبجکت، شماره حافظه آن آبجکت درنظر گرفته شده. یعنی مثلا وقتی آبجکتی داریم به نام hello، این آبجکت در خانه ۴۵ام (این عدد فرضی‌است، معمولا اعداد خیلی بزرگ‌تر هستند) از حافظه ذخیره شده. پس می‌دانیم که id آبجکت hello می‌شود ۴۵.خب که چه؟این مسئله از این جهت مهم است که پس می‌فهمیم ما آدرس حافظه هر آبجکت را داریم. و این خوشحال کننده‌ است. چون می‌توانیم کارهای نسبتا جالبی با استفاده از این آدرس بکنیم.برای انجام این بازی‌ها، ابتدا باید یکی از کتابخانه‌های نسبتا ناشناخته پایتون را فراخوانی کرد.‌این کتابخانه یکی از API های زبان پایتون با C است. اگر نمی‌دانید باید بدانید که پیاده‌سازی CPython با C نوشته شده و به همین دلیل زبان C را می‌توان به نوعی زبان مولد پایتون دانست. البته که پیاده‌سازی‌های دیگری هم از پایتون داریم که با زبان‌های دیگر هستند. مثل جایتون که با جاوا نوشته شده است.اگر این کتاب‌خانه برایتان جالب است، نگاه کردن به سورس آن خالی از لطف نیست. اما فعلا برای ما یکی از توابع این کتاب‌خانه مهم است. آن‌هم تابع memmove است. اگر خواننده دستی در C داشته باشد، علی‌القاعده باید از این اسم نسبتا طرز کار این تابع را حدس بزند. این اسم مخفف memory move است. به طور فنی یک بخشی از حافظه را جای بخش دیگری می‌گذارد. جابجا نمی‌کند! صرفا یکی را جای دیگری می‌گذارد.&gt;&gt;&gt; import ctypes as ct
&gt;&gt;&gt; import sys
&gt;&gt;&gt; a = &amp;quothello&amp;quot
&gt;&gt;&gt; b = &amp;quotsalam&amp;quot
&gt;&gt;&gt; size = sys.getsizeof(a)
&gt;&gt;&gt; ct.memmove(id(a),id(b), size)
140678768806768
&gt;&gt;&gt; a
&#039;salam&#039;همان‌طور که نظاره کردید، با بردن حافظه آبجکت a  به‌جای b توانستم مقدار داخل b را به a بدهم. همان‌طور که  گفتم این اتفاق دو طرفه نیست! یعنی الان مقدار داخل b همان salam  است و تغییری نکرده.همچنین تابع getsizeof هم اندازه آن آبجکت را به ما برمی‌گرداند. همان‌طور که می‌دانید یک رشته ساده در پایتون، خیلی‌هم ساده نیست. در واقع نوعی آبجکت است. و آبجکت اطلاعات زیادی را نگه می‌دارد. برای همین اندازه یک رشته ۵ حرفی مثل hello  بیشتر از ۵ بایت است. به طور فنی یک رشته خالی، ۴۹ بایت جا می‌گیرد. و به ازاء هر حرف جدید که به رشته اضافه شود یک بایت بیشتر می‌شود. این اندازه کل آبجکت در حافظه است. با همه مخلفاتش. این مسئله درمورد اعداد نیز صادق است. یک عدد کوچک مثل ۳، از آنجایی که در واقع یک آبجکت است، ۲۸ بایت فضا اشغال می‌کند. این فضای اشغال شده را با همان تابع getsizeof می‌توان فهمید.ربطش به دو به علاوه دو چیست؟ربطش این است که هر عدد نوعی آبجکت پایتونی است. لذا می‌توانیم به همین طریق جای اعداد را هم عوض کنیم! شاید بنظر عجیب برسد. اما واقعا می‌شود. &gt;&gt;&gt; ct.memmove(id(2), id(1), 28)
140678993844416
&gt;&gt;&gt; 2+2
2امیدوارم از این تردستی لذت وافر برده باشید.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Sat, 21 Aug 2021 00:22:11 +0430</pubDate>
            </item>
                    <item>
                <title>پروسه‌ها چگونه در کنار هم پیش می‌روند؟</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%BE%D8%B1%D9%88%D8%B3%D9%87-%D9%87%D8%A7-%DA%86%DA%AF%D9%88%D9%86%D9%87-%D8%AF%D8%B1-%DA%A9%D9%86%D8%A7%D8%B1-%D9%87%D9%85-%D9%BE%DB%8C%D8%B4-%D9%85%DB%8C-%D8%B1%D9%88%D9%86%D8%AF-czaiv3k7n52e</link>
                <description>این مطلب صرفا چکیده و خلاصه‌ای از مطالبی است که خوانده‌ام و برای تثبیت و درک بهتر مفاهیم سعی کردم آن‌ها را در قالب یک پست منتشر کنم. لذا احتمالا ایرادات فنی و حتی غیر فنی در آن وجود داشته باشد. از خواننده‌گان ممنون می‌شوم اگر این ایرادات و اشکالات را به من اطلاع بدهند.در نوشتار‌های قبل، تا حدی با مفاهیم پروسه‌ها و ریسه‌ها آشنا شدیم. در این پست راجع به نحوه مدیریت پروسه‌ها توسط سیستم‌عامل صحبت خواهیم کرد. در واقع چگونگی این مسئله که اجرا چندین پروسه در زمان واحد، میسر است و چگونه پروسه‌ها با وجود اطلاعات مشترک، کار یکدیگر را مختل نمی‌کنند.چرا اجرا چند پروسه به صورت همزمان دشوار است؟در اینجا منظور ما از همزمان، هر دو مفهوم parallel و concurrent است که در پست‌های قبل معرفی شدند. البته اطلاعات بیشتر درمورد تفاوت این دو مفهوم را در این لینک می‌توانید مطالعه کنید. برای بهتر درک کردن مشکلات اجرا شدن چند پروسه به صورت همزمان، می‌توان به مسئله شام فلاسفه اشاره کرد. اما این فقط یکی از انواع مشکلات احتمالی است. در واقع این مسئله، مشکل استفاده همزمان از منابع سیستم را نمایش می‌دهد. مثلا چگونه چند پروسه مختلف، همزمان از کارت شبکه، دیسک یا مانیتور استفاده می‌کنند. نوع دیگری از مشکلات که ممکن است رخ دهد داشتن داده مشترک بین دو پروسه است. برای تشریح بهتر این نوع از مشکلات، اجازه بدهید مسئله تولیدکننده و مصرف کننده را توضیح بدهم.مسئله تولیدکننده و مصرف‌کنندهفرض می‌کنیم ۲ پروسه داریم. یک پروسه مولد مقداری داده است. پروسه دیگر مصرف کننده داده‌هاست. در واقع پروسه مولد، در طول اجرا خود، داده‌ها را تولید کرده و داخل یک بافر قرار می‌دهد. پروسه مصرف‌کننده نیز، در طول اجرا خود، داده‌ها را یکی یکی از بافر می‌خواند و پردازش مورد نظر را روی آن‌ها انجام می‌دهد. از مفروضات دیگر مسئله، محدود بودن اندازه بافر است. اگر بافر پر شده باشد، پروسه مولد، منتظر می‌ماند تا بافر خالی شود و داده‌های بعدی را داخل آن قرار دهد. همچنین اگر همه داده‌های بافر توسط پروسه مصرف‌کننده خوانده شود، پروسه مصرف کننده منتظر می‌ماند تا داده جدید تولید شده و داخل بافر قرار گیرد. در واقع این بافر بین دو پروسه مشترک است و هر دو به آن دسترسی دارند.فرض می‌کنیم برنامه‌ای که برای پروسه مولد می‌نویسیم قطعه کد زیر باشد:while (true) {
     /* produce an item in next produced */
     if (count == BUFFER SIZE)
          continue;     /* do nothing */
     buffer[in] = next produced;
     in = (in + 1) % BUFFERـSIZE;
     count++;
}قطعه کد زیر هم برای پروسه مصرف‌کننده باشد:while (true) {
     if (count == 0)
        continue;    /* do nothing */
     next consumed = buffer[out];
     out = (out + 1) % BUFFERـSIZE;
     count--; 
     /* consume the item in next consumed */
}هر دو برنامه، به تنهایی درست کار می‌کنند. اما اگر هردو قرار باشد همزمان کار کنند. احتمال وقوع مشکل هست.فرض کنید متغیر count عدد ۷ باشد. بدین معنا که ۷ خانه از بافر پر شده است. اگر پروسه مولد بخواهد داده‌ای اضافه کند، به خانه ۸ام اضافه می‌کند و متغیر count را یکی بالا می‌برد. اگر پروسه مصرف‌کننده بخواهد داده‌ای را بخواند، از خانه ۷ام، داده را می‌خواند و متغیر count را یکی کم می‌کند. یعنی الان ۶ خانه از بافر پر است.حالا فرض کنید در شرایطی که متغیر count == 7 است، هر دو پروسه در حال اجرا و تغییر متغیر count باشند. در پردازنده وقتی قرار است متغیر count زیاد شود، ابتدا متغیر داخل یکی از رجیستر‌های پردازنده قرار می‌گیرد. سپس یکی به آن اضافه می‌شود. یعنی متغیر داخل رجیستر از ۷ به ۸ تغییر می‌کند. حالا مقدار داخل رجیستر، به متغیر count داده می‌شود. عینا مشابه همین فرایند برای کاهش مقدار count هم رخ می‌دهد.فرض کنید وقتی پروسه مولد، متغیر count را داخل رجیستر پردازنده بارگذاری می‌کند، مقدار داخل رجیستر ۷ است. در همین زمان پروسه مصرف‌کننده (که به طور همزمان در حال اجراست) متغیر count را داخل رجیستر دیگری از پردازنده قرار می‌دهد که دوباره همان ۷ است. حالا هر دو پردازش روی رجیسترها توسط پروسه‌ها جداگانه انجام می‌شود. یعنی پروسه مولد عدد رجیستر را یکی افزایش می‌دهد و می‌شود ۸، و پروسه مصرف‌کننده نیز آن را به ۶ تغییر می‌دهد. حالا هر دو پروسه می‌خواهند مقدار داخل رجیستر خود را به متغیر count نسبت دهند. نتیجه چه خواهد شد؟ واضح است که بلاخره یکی از این دو عملیات assignment باید بعد از دیگری انجام شود. و این یعنی متغیر count در آخر کار، یا مقدار ۶ خواهد داشت و یا مقدار ۸، در صورتی که جواب نهایی و درست همان ۷ است. چرا این مشکل رخ داد؟ چون متغیری تغییر داده شد که در حال تغییر داده شدن توسط دیگری بود. در واقع دو پروسه به طور همزمان دست به تغییر این متغییر کردند و شرایطی غیرقابل پیش‌بینی ایجاد شد. چون مشخص نیست نتیجه نهایی ۶ یا ۸ است. حتی در حالتی ممکن است اگر شانس بیاوریم، نتیجه نهایی همان ۷ باشد. اما قطعا این تضمین شده نیست که در اجرا مجدد برنامه همین خروجی را داشته باشیم.به شرایط‌ این چنینی، که دو پروسه می‌خواهند به داده واحدی دسترسی پیدا کنند و آن را تغییر دهند اصطلاحا race condition گفته می‌شود. طبیعتا وجود هرگونه race condition  در حالت عادی نامطلوب است.محدوده بحرانیمحدوده بحرانی، به هر بخشی از برنامه می‌گویند، که پروسه دسترسی خواندن یا تغییر در داده‌ای دارد که پروسه دیگری نیز همین دسترسی را به همان داده دارد. اگر بتوانیم پروسه‌ها را طوری پیش ببریم، که هیچ دو پروسه‌ای، به طور همزمان وارد محدوده بحرانی یکدیگر نشوند، می‌توانیم مطمئن باشیم که race condition رخ نخواهد داد. برای مثال در کدی که برای دو پروسه مولد و مصرف‌کننده نوشتیم، جایی که متغیر count افزایش و کاهش پیدا می‌کند، و جایی که این متغیر خوانده می‌شود، محدوده‌های بحرانی هر دو پروسه هستند. جایی که هر دو پروسه مشغول انگولک کردن داده مشترک هستند.همان‌طور که در تصویر بالا نمایش داده می‌شود، وقتی یک پروسه وارد محدوده بحرانی مربوط به پروسه دیگری می‌شود، سیستم‌عامل تا زمانی که پروسه اول از محدوده بحرانی خارج نشده پروسه‌های دیگری که قصد ورود به محدوده بحرانی دارند را متوقف می‌کند. به این خاصیت، می‌گویند انحصار متقابل، یا mutual exclusion. شیوه‌های مختلف برای ایجاد mutual exclusionقطع کردن تداخل‌ها (interrupt): شاید یکی از بدیهی‌ترین راه‌ها قطع کردن هرگونه تداخلی برای پروسه باشد. در حالت عادی، پردازنده هنگام اجرا یک پروسه، ممکن است آن را قطع کند و پروسه دیگری را پیش ببرد. اما اگر حداقل در مدتی که پروسه در محدوده بحرانی قرار دارد اینکار را متوقف کنیم شاید مشکل تا حدی حل شود.  البته که این راه حل موجب بروز مشکلاتی می‌شود. چون بدیهی است که امن نیست اجازه بدهیم یکی از پروسه‌های سیستم‌عامل تا مدت زمانی که داخل محدوده بحرانی قرار دارد بدون دخالت هیچ پروسه دیگری پردازنده را اشغال کند. و از طرفی، این راهکار برای پردازنده‌های چند هسته‌ای جوابگو نیست. چون ممکن است در هسته دیگری، پروسه دیگری وارد محدوده بحرانی شود.استفاده از قفل‌ها: یکی دیگر از راهکارها که بیشتر استفاده می‌شود قفل کردن متغیرهاست. وقتی پروسه‌ای وارد محدوده بحرانی می‌شود، متغیری که هر دو پروسه به آن دسترسی دارند را قفل می‌کند. اگر پروسه‌ای خواست آن متغیر را تغییر دهد، باید صبر کند تا متغیر از حالت قفل خارج شود. یکی از نقاط ضعف این شیوه، هنگامیست که دو پروسه همزمان سعی کنند یک متغیر واحد را قفل کنند. در این صورت دوباره ممکن است race condition پیش بیاید. اما نه برای متغیر، برای آن پرچمی که قفل بودن یا نبودن متغیر را نمایش می‌دهد (که البته به طور فنی آن‌هم خودش یک متغیر است).</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Fri, 13 Aug 2021 21:11:24 +0430</pubDate>
            </item>
                    <item>
                <title>مسئله شام فلاسفه</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D8%B4%D8%A7%D9%85-%D9%81%D9%84%D8%A7%D8%B3%D9%81%D9%87-eizrle6ve4yz</link>
                <description>در دو نوشتار قبل تا حدی با مفاهیم پروسه و ریسه (thread) آشنا شدیم. همچنین با دو مفهوم parallelism و concurrency آشنا شدیم و فهمیدیم که سیستم‌عامل‌های امروزی برای استفاده بهینه‌تر از منابع کامپیوتر تلاش می‌کنند پروسه‌ها و ریسه‌ها را تا حد امکان همزمان پیش ببرند. این هم‌زمانی در نهایت منجر به بروز مشکلاتی می‌شود. این مشکلات ناشی از منابع مشترک بین پروسه‌ها هستند. برای مثال دو پروسه سعی می‌کنند به‌طور همز‌مان از منبع A، استفاده کنند. بدیهی است که طراحان سیستم‌عامل باید برای جلوگیری از مشکل چنین موقعیت‌هایی را در نظر داشته باشد. یکی از مسائل سنتی و کلاسیکی که در این زمینه مطرح می‌شود مسئله شام فلاسفه است که در این مطلب به آن می‌پردازیم.فرض کنید ۵ فیلسوف دور یک میز مشغول خوردن شام هستند. همان‌طور که در تصویر دیده می‌شود، بین هر دو ظرف یک چنگال هست. زندگی هر فیلسوف تناوبی از تفکر و غذا خوردن است. هر فیلسوف مدتی مشغول تفکر است، و بعد می‌خواهد غذا بخورد. نحوه غذا خوردن هم به این شکل است که ابتدا سعی می‌کند چنگال‌های  سمت چپ و راست خود را بردارد، اگر موفق شد (یعنی اگر چنگال‌ها موجود بودند و توسط فلاسفه کناری در حال استفاده نبودند) برای مدتی مشغول غذا خوردن می‌شود. مسئله این است: آیا می‌توانی برنامه‌ای برای هر فیلسوف بنویسی، به طوری که هرگز هیچ‌کدام از فلاسفه در یک موقعیت گیر نکنند؟این مسئله اولین بار توسط ادگار دیکسترا در سال ۱۹۶۵ مطرح شد. البته صورت اولیه مسئله با چیزی که در بالا عنوان شد تفاوت‌هایی دارد اما کلیت مسئله همین است. حل مسئلهبرای حل این مسئله شاید بدیهی‌ترین راهی که به ذهن می‌رسد این باشد که هر فیلسوف ابتدا تلاش کند دو چنگال بدست آورد، اگر نتوانست، صبر کند تا دو چنگال موجود شوند، سپس مشغول خوردن شود. بعد از مدتی خوردن، چنگال‌ها را روی میز بگذارد و مشغول تفکر شود. #define N 5                                           / * number of philosophers * /
void philosopher(int i)
      {
      while (TRUE) {
            think( );
            takeـــfork(i);
            takeـــfork((i+1) % N);
            eat( );
            putـــfork(i);
            putـــfork((i+1) % N);
            }
      }این روش ساده، در عمل مشکل را حل نمی‌کند. چون در شروع کار، هر ۵ نفر، چنگال سمت راست خود را برمی‌دارند، و چون در کل ۵ چنگال داریم، چنگال‌ها تمام می‌شوند. حالا هر ۵ فیلسوف، منتظر می‌مانند تا چنگال سمت چپ خود آزاد شود، و این اتفاق هرگز نخواهد افتاد. چون نفر سمت چپ هم منتظر آزاد شدن چنگال سمت چپ خود است.این برنامه را می‌توان تغییر داد، به طوری که هر فیلسوف، وقتی می‌بیند چنگالی در کار نیست، چنگال موجود در دست دیگرش را نیز روی میز بگذارد و کمی صبر کند. اما باز هم این راه حل مشکل را حل نخواهد کرد. چون وقتی هر ۵ نفر همزمان شروع کنند، احتمالا هر پنج نفر متوجه می‌شوند که یک چنگال کم است. سپس هر ۵ نفر چنگال دیگر که در دست دارند را روی میز می‌گذراند و کمی صبر می‌کنند. و بعد از مدتی صبر کردن، دوباره همین اتفاق رخ می‌دهد. و عملا کاری از پیش نمی‌رود.برای این مسئله راه‌حل‌های زیادی تاکنون مطرح شده. یکی از راه‌حل‌هایی که می‌تواند تا حد زیادی مشکل را حل کند این است که زمان صبر کردن هر فیلسوف متفاوت از دیگری و در واقع تصادفی باشد. این کار تا حد زیادی مسئله را حل خواهد و کرد احتمال به‌وجود آمدن deadlock (حالتی که همه پردازش‌ها منتظر وقوع دیگری باشند و عملا هیچ‌کدام هیچ پیش‌روی نداشته باشند) بسیار پایین خواهد بود.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Sat, 07 Aug 2021 19:18:44 +0430</pubDate>
            </item>
                    <item>
                <title>نخ‌ها و مقایسه آن‌ها با پروسه‌ها</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%86%D8%AE-%D9%87%D8%A7-%D9%88-%D9%85%D9%82%D8%A7%DB%8C%D8%B3%D9%87-%D8%A2%D9%86-%D9%87%D8%A7-%D8%A8%D8%A7-%D9%BE%D8%B1%D9%88%D8%B3%D9%87-%D9%87%D8%A7-xydjgixecoyd</link>
                <description>این مطلب صرفا چکیده و خلاصه‌ای از مطالبی است که خوانده‌ام و برای تثبیت و درک بهتر مفاهیم سعی کردم آن‌ها را در قالب یک پست منتشر کنم. لذا احتمالا ایرادات فنی و حتی غیر فنی در آن وجود داشته باشد. از خواننده‌گان ممنون می‌شوم اگر این ایرادات و اشکالات را به من اطلاع بدهند.پیش‌نویس: تا جایی که من گشتم، متاسفانه ترجمه خوبی برای کلمه thread در زبان فارسی وجود ندارد. اما از آنجایی که نوشتن خود کلمه thread در رسم‌الخط انگلیسی برای نگارنده سخت است و خواندن کلمه ترد در رسم‌الخط فارسی احتمالا برای خواننده سخت باشد، ترجیح من استفاده از همین ترجمه نیم‌بند نخ بود. اگر کسی از خواننده‌گان ترجمه معقول‌تری از این کلمه می‌داند، ممنون می‌شوم به من اطلاع بدهد.در نوشتار قبلی تا حد مختصری سعی کردم مفهوم پروسه را تشریح کنم. در این پست قصد دارم تا درمورد نخ‌ها و جایگاه آن‌ها در مقایسه با پروسه‌ها در حد سواد خودم صحبت کنم. قبل از شروع صحبت درمورد خود مفهوم نخ، بنظرم بهتر است تفاوت concurrency و paralelism را بررسی کنیم.parallelism همانطور که از نامش پیداست، یعنی موازی کاری. با داشتن چند پردازنده (حداقل ۲ پردازنده) کامپیوتر می‌تواند چند پروسه را در آن واحد پیش ببرد. پس با این حساب می‌توان نتیجه گرفت روی کامپیوترهای تک‌پردازنده‌ای (single-processor) موازی کاری ممکن نیست.concurrency یعنی پیش بردن چند پروسه به صورت نوبتی در بازه‌های زمانی بسیار کوتاه. یعنی پردازنده بخش کوچکی از پروسه ۱ را انجام می‌دهد، بعد بخش کوچکی از پروسه ۲ را انجام می‌دهد. بعد دوباره برمی‌گردد به پروسه ۱ و بخش دیگری از آن را انجام می‌دهد. توجه داشته باشید که در این نوع پردازش، در آن واحد بیش از ۱ پروسه پردازش نمی‌شود. صرف دو پروسه به صورت نوبتی پیش برده می‌شوند. اما چون در بازه‌های زمانی بسیار کوتاه هر دو به نوبت اجرا می‌شوند، احتمالا برای کاربر این تصور به وجود می‌آید که هر دو پروسه به صورت همزمان اجرا می‌شوند. واضح است که این نوع از پردازش بر روی پردازنده‌های تک‌هسته‌ای هم قابل پیاده‌سازی است.همانطور که در پست قبل توضیح داده شد، جابجایی دو پروسه یا همان context switch هزینه زمانی برای پردازنده دارد. همچنین منابع بین دو پروسه کاملا تفکیک شده‌اند از یک‌دیگر بجز در مواقع خاص. لذا ارتباط بین دو پروسه سخت و زمان‌بر است، و از طرف دیگر هر پروسه بخش نسبتا زیادی از حافظه را اشغال می‌کند. این دو مسئله باعث شدند که مفهومی به نام نخ یا همان thread وارد دنیای سیستم‌عامل شود. نخ‌ها فرایند‌های پردازشی هستند. هر نخ حتما متعقل به یک پروسه هست. همچنین در خیلی از مواقع چندین نخ متعقل به یک پروسه هستند. یا به عبارت دیگر، یک پروسه می‌تواند، شامل چندین نخ باشد. نخ‌های متعقل به پروسه واحد، منابع زیادی را به صورت اشتراکی استفاده می‌کنند. مانند فایل‌های متعقل به آن پروسه و حافظه. اما هر پردازنده در آن واحد توانایی پیش‌بردن تنها یک نخ را دارد. لذا نخ‌ها در مدت زمان بهره‌برداری از پردازنده به صورت اشتراکی عمل نمی‌کنند. در واقع سیستم‌عامل در مدت زمانی محدود پردازنده‌ را در اختیار آن پروسه می‌گذارد. این وظیفه پروسه‌ است که این زمان را بین نخ‌های خود تقسیم کند. همچنین از آن‌جایی که در نهایت هر نخ پردازش جداگانه‌ای دارد، پس هر نخ register های خاص خود را در پردازنده لازم دارد و همچنین program counter خاص خود را دارد. این دو مورد هم جزو منابعی بودند که نخ‌ها به اشتراک نمی‌گذارند.شاید در ابتدا و با این تفاسیر، خواننده نخ‌ها را نوعی پروسه کوچک‌تر فرض کند. البته که این تصور خیلی‌هم نادرست نیست، اما دقیق‌هم نیست. شاید تصور بهتر و دقیق‌تر این باشد که ما اصولا ماهیت پروسه‌ها و نخ‌ها را متفاوت بدانیم. به این صورت که پروسه را صرفا اجتماعی از منابع کامپیوتر بدانیم. هر پروسه، صرفا بخشی از حافظه، فضایی از دیسک و تعدادی فایل است. همچنین مدت زمانی از پردازنده و دیگر دستگاه‌های کامپیوتر مانند کیبورد و مانیتور استفاده می‌کند. اجتماع این منابع، می‌شود یک پروسه. و خب واضح است که اجتماع منابع، هیچ پردازشی را به خودی خود به همراه ندارد. در نتیجه، یک پروسه به تنهایی هیچ‌کاری را از پیش نمی‌برد. چیزی که ماهیت پردازشی دارد، همان نخ‌ است. نخ‌ یک فرایند پردازشی، زیر مجموعه یک پروسه است، که از منابع پروسه در راستای اجرا برنامه و پیش‌بردن پردازش خود استفاده می‌کند. با این تعبیر، همه پروسه‌ها باید حداقل ۱ نخ داشته باشند. تصویر زیر تا حدی این موضوع را به نمایش می‌گذارد.سوالی که الان ممکن است برای خواننده پیش بیاید، این است که وقتی می‌توانیم یک پروسه جدید همراه با یک نخ، تولید کنیم، چه لزومی دارد به پروسه قبلی نخ‌های بیشتری اضافه کنیم؟در واقع همیشه این الزام وجود ندارد که به پروسه قبلی نخ اضافه کنیم. اضافه کردن پروسه در مقابل اضافه کردن نخ جدید، یک معامله است. هر کدام معایب و محاسنی دارند. به این معایب و محاسن در ادامه بیشتر می‌پردازیم.مزایای استفاده از نخ‌های بیشتر در یک پروسه بعضی وقت‌ها ما نیازی به پردازش سریع نداریم. بیشتر از آن نیاز به پاسخ‌گو بودن سریع کامپیوتر داریم. مثلا وقتی یک برنامه گرافیکی اجرا شده است و در هر لحظه ممکن است کاربر روی کیبورد چیزی بنویسد یا موس خود را جابجا کند، کامپیوتر پردازش زیادی برای انجام ندارد، اما مجبور است گوش به زنگ باشد تا هر وقت موس جابجا شد یا کاربر دکمه‌ای از کیبورد را فشرد، سریعا نتیجه آن را در صفحه نمایش بدهد. در این شرایط برای ما ارجحیت دارد قدرت پردازشی کامپیوتر بین چندین نخ تقسیم شود تا اینکه یک نخ قدرت پردازشی زیادی داشته باشد. در حالت دیگر فرض کنید کامپیوتری در حال محاسبه عدد اول بسیار بزرگی است. در این حالت احتمالا داشتن چند نخ و پردازش هم‌زمان آن‌ها کمک چندانی به ما نکند و اتفاقا به دلیل بار پردازشی context switch  بین هر دو نخ، احتمالا گزینه مطلوب‌تر این باشد که تمام توان پردازشی کامپیوتر در اختیار یک نخ باشد. اشتراک منابع، چیزی است که برای ما در بعضی موقعیت‌ها بسیار مهم است. بعضی برنامه‌های بزرگ، مانند یک مرورگر، احتمالا از منابع مشترکی استفاده می‌کنند اما یک نخ واحد قادر به پیش‌بردن تمام آن برنامه نیست. برای همین احتمالا هر صفحه‌ای که در یک مرورگر باز می‌شود نخ جدیدی در پروسه اصلی خود مرورگر باشد. اشتراک داشتن منابع از ۲ جنبه برای ما سودمند است. جنبه اول صرفه‌جویی در مصرف حافظه است، و جنبه دوم ارتباط سریع‌تر و راحت‌تر بین نخ‌ها. از آن‌جایی که حافظه اختصاص داده شده بین نخ‌های متعلق به یک پروسه مشترک است، ارتباط راحت‌تر و سریع‌تر بین نخ‌ها تا حدی واضح است. اما دلیل صرف‌جویی در مصرف حافظه در ادامه توضیح داده خواهد شد.همانطور که در تصویر بالا نشان داده شده است، نخ‌های متعلق به پروسه واحد، بخش program code و heap مشترک دارند. این باعث می‌شود استفاده از نخ‌های بیشتر در مقابل پروسه‌های بیشتر به صرفه‌تر باشد. در مثال قبل، فرض کنید یک مرورگر بجای نخ‌های متعدد، از پروسه‌های متعدد استفاده کند. این یعنی به ازاء هر پروسه، کل برنامه مرورگر در حافظه بارگذاری شود، که خب طبیعتا به صرفه نیست.معایب استفاده از نخ‌های بیشتر در یک پروسه همان‌طور که به عنوان یک مزیت، دسترسی آسان به اطلاعات دیگر نخ‌ها (در واقع به کل اطلاعات یک پروسه)، مطرح شد، می‌توان این را یک عیب و چالش نیز دانست. این مسئله ۲ مشکل برای ما به‌وجود می‌آورد. مشکل اول خطر تغییر اطلاعاتی است توسط دیگر نخ‌ها مورد استفاده است. وقتی هر نخ اجازه خواندن و نوشتن اطلاعات دیگر داده‌ها را دارد، طبیعتا احتمال خراب شدن داده‌ها بالا می‌رود. دومین مشکل وقتی رخ می‌دهد که دو نخ به طور هم‌زمان نیاز به دسترسی به یک داده خاص داشته باشند. به این حالت اصطلاحا race condition گفته می‌شود. این اتفاق معمولا موجب خراب شدن اطلاعات می‌شود. کند شدن پردازش، چیزی که احتمالا بدیهی است. طبیعتا در نگاه اول می‌توان متوجه این نکته شد که تقسیم زمان پردازش بین نخ‌های مختلف باعث می‌شود نهایتا پردازش هر کدام دیرتر انجام شود.همان‌طور که گفته شد، یکی از معایب استفاده از نخ‌های زیاد، نداشتن حافظه اختصاصی برای هر نخ است. این باعث می‌شود نخ‌ها امکان خراب کردن اطلاعات دیگر نخ‌ها را داشته باشند. برای اینکه این مشکل تا حدی حل شود، حافظه‌ای با نام Thread local storage ابداع شد. این حافظه در واقع حافظه اختصاصی هر نخ محسوب می‌شود که دیگر نخ‌ها به آن دسترسی ندارند. اگرچه این ابداع، تا حدی مشکل ما را حل می‌کند، اما بازهم باید توجه داشت، که حافظه TLS خیلی محدود و کوچک است.مدل استخر نخ‌ها برای استفاده بهینه‌تر از نخ‌ها (چقدر نخ ترجمه مزخرفیه!)ایجاد یک نخ جدید، برای کامپیوتر هزینه دارد. اختصاص دادن یک حافظه اختصاصی و همچنین اضافه کردن اطلاعات نخ جدید به Process control block پروسه مادر و بسیاری دیگر از جزئیات آن زمان‌بر هستند. برای همین یک استراتژی برای استفاده از نخ‌های زیاد ایجاد یک استخری (یا در واقع مخزنی) از نخ‌هاست. فرض کنید یک سرور دارید. به ازاء هر درخواستی که از بیرون میاید، این سرور قرار است یک نخ جدید ایجاد کند و نخ جدید سعی کند درخواست را رتق و فتق کند. اینکار با توجه به سربار بالای ایجاد یک نخ جدید احتمالا خیلی منطقی نباشد. کاری که شاید بهتر باشد این است که در ابتدا تعداد زیادی نخ ایجاد کنیم، هرگاه درخواستی از بیرون آمد، یکی از این نخ‌ها مشغول بررسی و پاسخ دادن به آن درخواست می‌شود. در واقع کار ایجاد یک نخ جدید، در ابتدا برنامه انجام شده، و فقط باید یک نخ‌ را صدا زد.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Sat, 31 Jul 2021 01:10:37 +0430</pubDate>
            </item>
                    <item>
                <title>پروسه‌ها در دنیای سیستم‌عامل چیستند؟</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%BE%D8%B1%D9%88%D8%B3%D9%87-%D9%87%D8%A7-%D8%AF%D8%B1-%D8%AF%D9%86%DB%8C%D8%A7%DB%8C-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D8%B9%D8%A7%D9%85%D9%84-%DA%86%DB%8C%D8%B3%D8%AA%D9%86%D8%AF-y2gmzwhyaux4</link>
                <description>این مطلب صرفا چکیده و خلاصه‌ای از مطالبی است که خوانده‌ام و برای تثبیت و درک بهتر مفاهیم سعی کردم آن‌ها را در قالب یک پست منتشر کنم. لذا احتمالا ایرادات فنی و حتی غیر فنی در آن وجود داشته باشد. از خواننده‌گان ممنون می‌شوم اگر این ایرادات و اشکالات را به من اطلاع بدهند.پروسه‌ها احتمالا یکی از بنیادی‌ترین مفاهیم در حوزه سیستم‌عامل محسوب می‌شوند. لذا ابتدا خود مفهوم پروسه را تعریف می‌کنیم و بعد از آن به توضیحات جانبی و دقیق‌تر می‌پردازیم.پروسه یا همان process چیست؟شاید یک تعریف خوب اما اندکی غیردقیق از پروسه، &quot;هر برنامه در حال اجرا&quot; باشد. توجه داشته باشید که خود &quot;برنامه&quot; به خودی خود صرفا اطلاعات خامی محسوب می‌شود که جایی در حافظه یا دیسک کامپیوتر ذخیره شده. وقتی تبدیل به یک پروسه می‌شود که اجرا شود. برای مثال یک برنامه برای محاسبه nامین عدد از دنباله فیبوناچی احتمالا تعدادی instruction -دستوراتی که پردازنده کامپیوتر می‌تواند آن‌ها را اجرا کند- هست که در یک فایل در سیستم ذخیره شده است. وقتی این برنامه اجراء می‌شود، آن instruction ها به ترتیب در پردازنده اجرا می‌شوند. در این لحظه ما برنامه را اجراء و یک پروسه ایجاد کردیم.تعبیر دیگری که از پروسه می‌توان داشت، task یا وظیفه‌ای است که به کامپیوتر محول شده تا آن را به انجام برساند. برای مثال کپی کردن یک فایل در کامپیوتر وظیفه‌ای است که به کامپیوتر محول می‌شود و در نتیجه یک پروسه است.از آن‌جایی که هر برنامه در حال اجرا احتمالا روزی متوقف می‌شود، پس هر پروسه عمر محدودی دارد. وقتی instruction های آن برنامه در حال اجرا تمام شوند، یا وظیفه‌ای که کامپیوتر قرار بود انجام بدهد انجام شود، عمر پروسه تمام می‌شود.هر پروسه، اطلاعاتی دارد که در ادامه بیشتر درمورد آن‌ها صحبت خواهیم کرد، این اطلاعات در حافظه کش پردازنده یا حافظه اصلی خود کامپیوتر ذخیره می‌شوند. پردازنده کامپیوتر در هر مرحله از اجراء پروسه نیاز به دسترسی به این اطلاعات دارد. به همین علت معمولا پروسه در حال اجراء اطلاعاتش داخل حافظه کش پردازنده ذخیره می‌شود. چون حافظه کش فاصله خیلی کمتری با پردازنده دارد بسیار سریع‌تر از حافظه اصلی کامپیوتر است. ابتداء اجرا هر برنامه، برنامه‌ای موسوم به loader، اطلاعات مربوط به آن برنامه - که قرار است اجرا شود- را از دیسک می‌خواند و در حافظه کش پردازنده یا حافظه اصلی سیستم می‌نویسد. بدون انجام چنین کاری، پردازنده برای دسترسی به اطلاعات هر پروسه مجبور است با دیسک کامپیوتر سر و کله بزند و این کار شدیدا کامپیوتر را کند خواهد کرد، طوری که عملا غیرقابل استفاده خواهد شد. شکل زیر تا حدی این مسئله را توضیح می‌دهد.شمای کلی کار loader اطلاعات مربوط به هر پروسههر پروسه، برنامه‌ای در حال اجراء است. هر برنامه‌ای اطلاعاتی دارد. این اطلاعات شامل موارد زیر است:خود داده خام برنامه (فایل اجرائی آن، که غالبا به صورت یک فایل باینری هست)متغیر‌های برنامه (اعم از متغیرهای مقداردهی شده و مقداردهی نشده، initialized و uninitialized) حافظه stack (مخصوص اجرا توابع) حافظه heap (حافظه‌ای که به صورت پویا در زمان اجرا برنامه تغییر اندازه می‌دهد بر حسب نیاز) حافظه اختصاص داده شده به خود داده خام برنامه (مورد اول) و متغیرهای برنامه (مورد دوم) ثابت هستند و در زمان اجرا برنامه تغییر نمی‌کنند. اما مورد سوم و چهارم تغییر می‌کنند بسته به وضعیت پروسه. شمای کلی این اطلاعات در حافظه به شکل زیر است:حافظه استک و هیپ میتوانند در اندازه محدودی تغییر ظرفیت دهند.همچنین هر پروسه برای تعامل با پردازنده کامپیوتر و سیستم‌عامل، اطلاعات اجرائی خود را در بخشی از حافظه با نام process control block یا PCB ذخیره می‌کند. PCB شامل اطلاعات زیر است: وضعیت پروسه (process state) که در ادامه توضیح خواهیم داد آدرس instruction بعدی که پردازنده باید اجرا کند (program counter) رجیسترهای پردازنده (اطلاعاتی که پردازنده برای اجرا instruction بعدی نیاز دارد، مانند اشاره‌گرهای برنامه) اطلاعات فایل‌های باز مربوط به این پروسه یا همان IO status اطلاعات اجرایی هر ئروسه در PCB ذخیره میشود.وضعیت هر پروسههر پروسه به طور کلی احتمالا در یکی از وضعیت‌های زیر هست:شروع : پروسه تازه ایجاد شده و هنوز پردازش آن شروع نشده. در حال اجراء: پروسه در حال اجرا توسط پردازنده است. انتظار: پروسه منتظر چیزی است. مثلا منتظر گرفتن ورودی از کاربر یا خواندن داده‌ای از فایل یا دریافت اطلاعاتی از شبکه. آماده: پروسه آماده اجرا شدن توسط پردازنده است. اما هنوز اجرا نشده.  پایان: اجرا پروسه به اتمام رسیده است.تداخل‌ها یا interruptهر پردازنده در هر لحظه تنها می‌تواند یک پروسه را پیش ببرد. درست برعکس حافظه که می‌توان آن‌را بین پروسه‌های مختلف در آن واحد تقسیم کرد. این محدودیت برای کامپیوترهای امروزی ما خیلی بزرگ است. ما انتظار داریم کامپیوترهای ما در هر لحظه بتوانند چندین پروسه را پیش ببرند. به همین منظور نیاز به تداخل یا interrupt داریم. تداخل یعنی، حین اجرا شدن یک برنامه، سیستم‌عامل تشخیص می‌دهد پروسه دیگری اولویت بیشتری دارد، و انجام پروسه قبلی را نصف نیمه، رها می‌کند و پروسه جدید را - که احتمالا اولویت بیشتری داشته- پیش ببرد. به ازاء هر تداخل، زمانی از پردازنده گرفته می‌شود تا اطلاعات پروسه قبلی را در حافظه اصلی کامپیوتر قرار بدهد (save) و اطلاعات پروسه جدید را در رجیسترهای خود بارگذاری کند (load). به فرایند تعویض اطلاعات برای اجرا پروسه جدید و ذخیره حالت پروسه قبلی context switch گفته می‌شود. باید توجه داشت که این فرایند باید طوری انجام شود که وضعیت پروسه قبلی بدون تغییر در حافظه ذخیره شود تا در آینده بتوان دوباره پردازش آن را از همان نقطه آخر ادامه داد.سوالی که اینجا ممکن است پیش بیاید این است که سیستم‌عامل با چه منطقی تشخیص می‌دهد باید پروسه دیگری را جای پروسه کنونی اجرا کند. سیستم‌عامل با برنامه‌ای به‌نام زمان‌بند پردازنده یا cpu scheduler، الویت اجرایی پروسه‌ها را تعیین می‌کند و آن‌ها را بنابر الگویی مشخص اجرا می‌کند. اطلاعات بیشتر درمورد cpu scheduler احتمالا به صورت یک پست در آینده منتشر شود.ارتباط پروسه‌ها با یک‌دیگرحال می‌دانیم که در مدت زمان مشخصی، احتمالا چند پروسه به نوبت در پردازنده اجرا می‌شوند. این پروسه‌ها در بعضی حالات نیاز دارند تا با هم صحبت کنند (اطلاعاتی را بین یک‌دیگر منتقل کنند). به ارتباط بین پروسه‌ها اصطلاحا IPC (interprocess communication) گفته می‌شود. این ارتباط، غالبا به دو صورت کلی انجام می‌شود: حافظه اشتراکی یا shared memory : در این حالت، دو پروسه، قسمتی از حافظه را به صورت اشتراکی استفاده می‌کنند. هر پروسه می‌تواند برای انتقال اطلاعات، داده مورد نظر خود را در بخش حافظه اشتراکی بنویسد. در این حالت، پروسه دیگر دسترسی خواندن این داده را دارد و می‌تواند این داده را بخواند. این نوع ارتباط بین دو پروسه، از نظر پیاده‌سازی برای سیستم‌عامل نسبتا ساده است، اما کار برای برنامه‌نویسان برنامه‌ها سخت می‌شود. چون خودشان باید قواعد مشخصی برای استفاده از حافظه اشتراکی را تنظیم کنند. توجه داشته باشید که به طور پیش‌فرض، پروسه‌ها به حافظه یک‌دیگر دسترسی ندارند. هر پروسه به بخشی از حافظه که فقط متعلق به خودش هست دسترسی دارد. ارسال پیام یا message passing system: همان‌طور که از نامش پیداست، این مکانیزم، به برنامه‌نویس اجازه می‌دهد تا داده مشخصی را برای یک پروسه مشخص ارسال کند. این مکانیزم برای پیاده‌سازی خود سیستم‌عامل سخت‌تر است اما کار برای برنامه‌نویسان ساده‌تر می‌شود. چون دیگر نیاز به تنظیم و پیاده‌سازی قوانین خود نیست. صرفا باید system call مخصوص ارسال پیام به پروسه مشخص را صدا کند. وظیفه ارسال پیام به پروسه مقصد، با سیستم‌عامل است.منبع من  برای مطالعه این موضوع اکثرا فصل سوم از کتاب Operating System Concepts، ویرایش دهم بود. </description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Fri, 23 Jul 2021 20:57:20 +0430</pubDate>
            </item>
                    <item>
                <title>ویرگول عالی نیست</title>
                <link>https://virgool.io/@riahiamirreza79/%D9%88%DB%8C%D8%B1%DA%AF%D9%88%D9%84-%D8%A7%DB%8C%D8%B2-%D9%86%D8%A7%D8%AA-%DA%AF%D8%B1%DB%8C%D8%AA-tpdqkkkxvgir</link>
                <description>ویرگول تار است!ویرگول خوب است.ویرگول عالی نیست.ویرگول توانایی عالی شدن را دارد!و در راستای این عالی شدن،پیشنهاد هایی را می خواهم در این مطلب مطرح کنم که شاید برای توسعه دهندگان ویرگول جالب و در بهترین حالت مفید باشد. البته من کسی هستم که بسیار با فضای وب و مخلفات آن فاصله دارم و یحتمل  از هزینه های زمانی و مالی این پیشنهاد ها خبر نداشته باشم، اما به هر حال بنظرم حداقل گفتن این ها خالی از فایده نیست.پیشنهاد مطالعهقابلیتی که بتوانم به کسی یک مطلبی را برای مطالعه پیشنهاد کنم، منظور در واقع همان تگ کردنی هست که در اینستاگرام هم هست اما بنظرم این قابلیت دوتا تفاوت با تگ کردن دارد.اول اینکه بخش کامنت ها بنظرم نباید با همچین چیزی الکی پر شود، این پیشنهاد کردن در قسمت نظرات ظاهر نخواهد شد و  فقط در بالای متن تعداد دفعاتی را که ملت این مطلب را پیشنهاد کرده اند نوشته خواهد شد مثلا بالای یک مطلب هست:این مطلب n دفعه برای مطالعه پیشنهاد شده است. دوم اینکه  اصطلاح تگ کردن برای فضایی مانند اینستاگرام شاید مناسب باشد، اما اگر ویرگول قصد داشته باشد فضایی علمی به دور از شلوغی اینستاگرام داشته باشد، بهتر است که نام کاملا متفاوتی برای این قابلیت بگذارد.مطالب زنجیره ای یا سریالیمطالب زیادی در ویرگول هست که یا آموزشی هستند و یا داستانی که در چندین قسمت منتشر می شوند. از جمله همین تند خوانی خودم. (بروید، بخوانید، لایک کنید، حال کنیم(:)  مثلا برای مطالبی که دنباله دار هستند ، یک زنجیره (یا هر اسمی که حال می کنید) بسازیم ، و در آن توضیحاتی درمورد کل مجموعه ارائه بدهیم ، و به ملتی که مطالب قسمت های قبل را خوانده اند درصورتی که مطلب جدید منتشر شد اطلاع داده شود. و خیلی امکانات جانبی دیگر از این قبیل که خودتان که اوستای کار هستید بلدید.نوشته های هجو...این گزینه بستگی به استراتژی و خط مشی ویرگول دارد، اگر هدف ویرگول ساختن محیطی علمی همانند مدیوم هست، بنظرم اجراء این گزینه کمی ضروری به نظر می رسد. مطالب هجو در ویرگول متاسفانه زیاد هستند،  اینجا فیسبوک نیست که مثلا وقتی از یک بیت شعر لذت می برید، آن را در ویرگول بگذارید و تمام. یا مثلا تصمیم گرفته اید از این به بعد روزانه هشت لیوان آب بنوشید، آن را در ویرگول اعلام می کنید و انتظار دارید ملتی آن  را بخوانند. نوشتن شعر اصلا بد نیست، اما حداقل دو سه خط، سه چهار خط، پنج شش خط، هفت هشت خط در مورد آن بنویسید، یا نظرتان را هر  چند غلط، بگویید. کسی شما را بابت حرف اشتباهتان اعدام نخواهد کرد. و یا همین روزانه هشت لیوان آب نوشیدن بسیار کار خوبی است، اما بهتر نیست بعد از اینکه مدتی این عادت را انجام دادید و تاثیرات آن را در زندگی خود مشاهده کردید ،آن وقت که تجربه ای غنی دارید، آن را به اشتراک بگذارید؟  مطلب منظورم لزوما نه مطلبی که علمی باشد و پر از آمار و ارقام و کلمات انگلیسی، مثلا آقای خالقی که چند روزی هست نوشته هاشون رو دنبال می کنم خیلی از مطالبشون علمی نیست ولی پشتش تفکری هست،یا یک تجربه ای که برای مخاطب جالب هست و  درگیرش می کند.                  حس می کنم زیاد حرف زدم اما لُب کلام اینکه ویرگول خواهشا نوشته های هجو را یک جوری شناسایی کن و در بخش پیشنهادات آن ها را به نمایش نگذار. سپاس :)صاحب نظر داشته باشیم!در قسمت نقشه راه دیدم دسته بندی مطالب جزء اولین اولویت های ویرگول هست که خیلی هم خوب هست. به نظر بنده حقیر کسی که مثلا در حوزه برنامه نویسی (که اتفاقا بازارش تو ویرگول داغه!) چندین  مطلب منتشر کرده، زمان زیادی صرف مطالعه مقالات مربوط به برنامه نویسی کرده، در زیر آن ها نظر گذاشته، دیگر کسانی که در حوزه برنامه نویسی هستند او را دنبال می کنند و نوشته هایش را می پسندند و دیگر معیار ها و ملاک ها را داشته ، در حوزه برنامه نویسی( فقط درحوزه برنامه نویسی، یعنی حوزه تخصصی خودش) نظرش سنگین تر از  من باشد که اصلا نه مطلبی در این زمینه خوانده ام و نه نوشته ام. مثلا هر لایک او پنج برابر لایک من ارزش داشته باشد. یا مطالبی که او منتشر می کند بیشتر به ملت نشان داده شود.آمار مطالعات منیک چیزی که خیلی دوست دارم از آن خبر داشته باشم این است که من از اول تا حالا چند ساعت در ویرگول مطالعه داشته ام؟ در چه زمینه هایی بیشتر از همه مطالعه کرده؟ میزان مطالعه هفتگی من چند کلمه بود؟ از تمام مطالبی که باز کرده ام در ویرگول چندتای آن هارا مطالعه کردم بعد بستم؟ این ها آماری هستند که ویرگول می تواند در اختیار ما بگذارد ( حتی میتونه پول هم بگیره در ازاش)امیدوارم ویرگول این مطلب را بخواند و ناشی گری های ما را در خصوص پیشنهادات متذکر شود . که البته انصافا ویرگول در جواب دادن به نظرات و واکنش ها بسیار خوب عمل می کند و دمَش گرم! https://www.nima.today/صفحه‌های-پرفالوئر-چطور-مدیریت-میشوند/ این مطلب را با اینکه بی ربط است مطالعه کنید و قدر ویرگول را بدانید که همیشه جواب کاربران را سریعا می دهد. امیدوارم در آینده که سرش بیشتر شلوغ می شود هم همینطور باشد. نکته آخر، اگر شما هم ایده ای برای ویرگول داشتی آن را با #ایده_هایی_برای_ویرگول منتشر کن. تشکر مؤكد.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Fri, 15 Jun 2018 18:47:51 +0430</pubDate>
            </item>
                    <item>
                <title>تند خوانی و مخلفات (قسمت دوم)</title>
                <link>https://virgool.io/@riahiamirreza79/%D8%AA%D9%86%D8%AF-%D8%AE%D9%88%D8%A7%D9%86%DB%8C-%D9%85%D8%B1%D8%B6-%D9%88-%D8%AA%D9%86%D8%AF-%D8%AE%D9%88%D8%A7%D9%86%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-x633bp2odzkl</link>
                <description>انصافا عکس خوبیه! ولی یکم بی ربط.درقسمت قبل، ضمن تعریف تند خوانی و توضیحاتی پیرامون آن، به بحث تند خوانی پرداختیم. برای یادآوری وارد لینک زیر شوید و مطالعه کنید. (اگر مطلب قبلی رو مطالعه نکردید ، اول اون رو بخونید) https://virgool.io/@riahiamirreza79/تند-خوانی-چیست-و-چرا-zfej0rtftoew  در این بخش کمی بیشتر وارد حیطه فنی می شویم و توضیحات اجمالی را تا حد ممکن کوتاه میکنیم.فقط  قبل از شروع من به سوال آقای مباشری که در نوشته قبلی پرسیدند پاسخ میدهم. سوالی که برای خودم هم سوال و بود و جوابش رو نمیدونستم اما چند روز گذشته تقریبا متوجه شدم. ایشون پرسیدند&quot; آیا خط بردن ( که خود نیازمند هماهنگی دست و چشم و فعالیت مغز است) خود عامل کاهش سرعت نخواهد بود؟&quot; خب الان کامل توضیح میدم.من در نوشته قبلی نوشته قبلی طوری خط بردن رو مطرح کردم که انگار عادتی هست که باید در ما برای همیشه ایجاد بشود و در نهایت ما باید خط ببریم. اما یافته های جدید مبنی بر این است که خط  بردن صرفا یک حرکت تمرینی است که فواید بسیار دارد اما در نهایت ، وقتی با سرعت های بالا مطالعه می کنید خط بردن تقریبا کار محالی است.فواید خط بردنخط بردن دو  تغییر در نحوه مطالعه شما ایجاد می کند، و پس ایجاد آن تغییرات دیگر کار بلا استفاده ایست.گم و گور شدن، در نوشته قبلی هم به این نکته اشاره کردیم اما به عنوان موانع تند خوانی. شما وقتی خط می برید برای مدتی طولانی کم کم چشمانتون تربیت می شوند که در یک  راستای مشخص و بدون حرکت اضافی مطالعه کنند. این مسئله که در نوشته قبلی گفتم &quot;به نظرم خیلی مهم نیست&quot; خیلی مهم است ! چون که چشم ما علاوه بر گم گور شدن بین خطوط یک سری حرکات غیرارادی هم دارد که در نظر ما شاید پنهان باشند.خط بردن این دسته از حرکات رو هم از بین می برد.توانایی زیاد کردن سرعت چشم. هر مکث کردن روی یک کلمه ( که بهش میگن:saccade)  تقریبا 1/4 ثانیه یا 0.25 صدم آن طول می کشد. ما با خط بردن می توانیم این مدت زمان رو به طور محسوسی کاهش دهیم. یعنی وقتی سرعت حرکت دست ما سریع تر از حرکت چشم باشد، به چشم فشار وارد می شود و مجبور می شود سریع تر حرکت کند. در ابتداء درک مطلب کاهش می یابد اما اگر همین روند را در مطالعه ادامه دهیم کم کم درک مطلب به حالت قبل می رسد.تقویت عضلات چشمچند تا تمرین برای تقویت عضلات چشم هست که من برای  شما درشت هاش رو سوا کرده و خدمتتون عرض میکنم. فقط قبل از شروع توضیحات فنی، یک کار خیلی ساده هست برای گرم کردن عضلات چشم. برای اینکه چشم ها وسط تمرین گیر پاژ نکنند.برای گرم کردن چشم قبل از تمرین یک کتاب رو مقابل خودتون باز کنید، و چشمانتون رو از گوشه های صفحه به صورت ضربدری بچرخانید. یعنی یک چیزی تو مایه های این عکس پایین: چشم هاتون رو در جهت پیکان ها بگردونید.این کار رو برای حدودا 15 ثانیه انجام بدید تا عضله های چشمتون گرم شوند و بتوانید تمرین های بعدی رو انجام بدید.حرکت چشم روی خطوط برای اینکار شما باید چشمانتون رو با بیشترین سرعتی که توان دارید رو خطوط کتاب ( یا هر چیزی)  حرکت بدید، هیچ نیازی به خواندن کلمات نیست، فقط مطمئن شوید که از روی کلمات می گذرید.بی کپشن!از دیگر تمرین هایی که برای چشم هست نگاه کردن به این ویدئو کوتاه زیر هست، اگر امکانش هست دانلود کنید و روزانه یک بار کامل نگاه کنید. https://www.aparat.com/v/u0s6S خط بردن همراه با حرکت چشم روی خطوط ماحصل این تمرین همان دو فایده ای از خط بردن است که بالاتر اشاره کردم. برای انجام بهتر این تمرین کتاب را وارونه مقابل خود بگیرید و سعی کنید با بیشترین سرعت ممکن انگشت سبابه خود را روی خطوط حرکت دهید و چشمانتون بالای انگشت رو دنبال کنند. درک مطلب در این تمرین و تمرین بالایی اصلا مهم نیست برای همین کتاب رو وارونه مقابل خود میگیریم.تمرین وراندازی و براندازی (اسکن کردن)در تند خوانی، یکی از مهم ترین مهارت ها یافتن کلید واژه های مهم در متن است. طبق چیز هایی که دانشمندان اعلام کردن، ما در یک متن دو دسته کلمه داریم:کلمات محتوایی (content words) کلماتی که کلید واژه های متن هستند و اصل محتوای متن داخل اون هاست.کلمات عملکردی(function words) کلماتی که معنای مستقلی  ندارند و فقط ارتباط بین &quot;کلمات محتوایی&quot; رو مشخص    می کنند. مثل : از،به،که،در ...نمونه فرنگیش.برد شما در تند خوانی این است که بتوانید هر چه سریع تر کلمات محتوایی را تشخیص دهید و لُب کلام را دریابید .برای تقویت مهارت وراندازی متن یا همون اسکن کردن هم تمریناتی وجود دارد. اصلی ترین تمرین هم خود اسکن کردن یک متن هست، سعی کنید واژه های کلیدی یک بند از یک کتاب رو با سرعت بالا پیدا کنید. اما یک تمرین دیگر هم هست.سعی کنید در عکس زیر به ترتیب اعداد رو از یک تا پنجاه پیدا کنید، با سرعت هر چه بیشتر:یک بازی ام بود شبیه این...برای انجام همچین تمرینی باید  اول روی یک کاغذ اعداد رو تا جای ممکن بدون هیچ روندی و کاملا تصادفی ( که خب امکان نداره) بنویسید ، و بعد از چند ساعت که تقریبا فراموش کردید جای اعداد رو ، بیاید و تمرین رو انجام بدید. فقط بهتر هست که هر بار زمان  رو بگیرید تا روند پیشرفت خودتون رو مشاهده کنید.سپاس غلیظ از اینکه متن رو تا اینجا دوباره مطالعه کردید. من منابع بیشتری رو برای تند خوانی پیدا کردم که یحتمل به کارتون بیاد. یکی از بهترین منابع برنامه های آقای دکتر سیدا هست که از تلویزیون سال ها پیش پخش شده ولی خوشبختانه توی اینترنت هست. از لینک زیر میتونید برنامه هارو مشاهده کنید:http://mkz.ir/post/95این هم لینک آپارات:https://www.aparat.com/v/bpvf3این هم فایل های صوتی همین برنامه ها:http://goodtoknow.ir/tond-khani/منابعی که توی این مطلب و مطلب قبل معرفی کردم منابع خوب و جامعی هست ، ولی اگر باز هم دنبال منبع می گردید باید فیلتر شکن رو روشن کنید و وارد سایت ضاله  چی چی یوب شوید و عبارت &quot;how to speed read&quot; رو جستجو کنید.     اگر هم دسترسی به این سایت ندارید میتونید توی مدیوم این عبارت رو جستجو کنید، اونجا هم بسیار اطلاعات زیاد و مفیدی وجود دارد.</description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Wed, 13 Jun 2018 19:07:59 +0430</pubDate>
            </item>
                    <item>
                <title>تند خوانی؟ چیست و چرا؟</title>
                <link>https://virgool.io/BookReading/%D8%AA%D9%86%D8%AF-%D8%AE%D9%88%D8%A7%D9%86%DB%8C-%DA%86%DB%8C%D8%B3%D8%AA-%D9%88-%DA%86%D8%B1%D8%A7-zfej0rtftoew</link>
                <description>حدودا دو ماه پیش بود که در اینترنت گشت و گذاری داشتم، که نگاهم به  مطلبی خورد که ذهنم را تا الان که در حال نوشتن این مطلب هستم درگیر کرده است . دقیق عنوان مطلب را یاد ندارم ولی  مربوط به افزایش سرعت مطالعه و مخلفاتش بود. از آن روز به بعد تقریبا هر وقت فرصت می کردم می رفتم در اینترنت و درمورد تند خوانی مطلب میخوندم. و چون احساس کردم جای همچین مطلبی توی ویرگول خالی هست خواستم تا چکیده ای از مطالعات این دو ماهه خودم را خدمتتان عرض کنم.فقط قبل از شروع به دو نکته باید اشاره کنم:_من تخصصی در زمینه تند خوانی ندارم، فقط کسی هستم که چندین ساعت در این حوزه مطالعه کرده، پس احتمال زیاد شمایی که بیشتر از من تخصص داری  ایراداتی در این متن خواهی دید، خوشحال خواهم شد اگر به من بگوئید!_از آن جایی که مطالبی را که عرض میکنم تقریبا هیچ کدام از خودم نیست، سعی میکنم تمام منابعی که از آن ها  استفاده کردم را در آخر مطلب ذکر کنم(ولی واقعا سخته چون خیلی پراکنده مطالعه کردم)                                تند خوانی چیست و چرا؟در مورد تند خوانی نظرات متعددی توی اینترنت هست. عده ای معتقدند که اصلا تند خوانی  امکان نداره، و در نهایت شما میتونی با درک مطلب بسیار پایین، مطلب رو یک ور اندازی بکنی(skimming).اما عده  دیگری که شمارشون دو-سه برابر گروه اول هست معتقد هستند که با تمرین میشه سرعت مغز رو هم بالا برد و در نهایت در مدت زمان کم حجم مطلب بیشتری رو خوند، با درک مطلب قابل قبول.در جواب به اون دسته ای که اعتقاد دارند وقتی سرعت ورودی اطلاعات بالا میره، تمرکز پایین میاد و ما از متن چیزی نخواهیم فهمید، باید گفت:مغز ما در مدت زمان محدود، قادر به دریافت مقدار محدودی از اطلاعات هست، اگر مقدار بیش از حد اطلاعات واردش کنیم،  مغز توان تجزیه و تحلیل کافی رو نداره و قسمتی از اطلاعات رو متوجه نمیشویم.اما اگر کمتر از مقداری که گنجایش داره اطلاعات واردش کنیم، مقداری که خالی میمونه باعث حواس پرتی ما میشه. خب میدونم این کادر بالا کامل شمارو قانع نکرده، اما در ادامه متن به شما میگم که شما میتونید با برداشتن موانعی اون محدوده گنجایش مغز رو بالاتر ببرید.                             خب ، از کجا شروع کنم؟اول از همه شما باید با مفهوم سرعت مطالعه آشنا بشید.این مفهوم  یعنی سرعتی که ما مطالعه میکنیم. خیلی سنگین نبود :) دقیق تر اگر بخوام توضیح بدم، سرعت مطالعه که با واحد word per minute)WPM) یعنی تعداد کلماتی که در هر دقیقه میخونیم. و تقریبا همه جا برای شروع کار تند خوانی، سرعت اولیه رو اندازه گیری می کنند که خب منطقی هم هست.نحوه محاسبه سرعت مطالعه: برای اینکار ابتداء باید یک کتاب ساده(ترجیحا داستان) بردارید و کلمات سه خط رو بشمرید، بعد میانگین اون سه خط رو حساب کنید.  حالا یک  زمان دلخواه(برحسب ثانیه) بگیرید و مشغول مطالعه شوید پس از تمام شدن اون زمان با توجه به میانگین کلمات هر خط، تعداد کلماتی رو که توی اون یک دقیقه خوندید رو محاسبه کنید. سپس تعداد کلمات رو تقسیم بر زمان برحسب ثانیه کنید.  فرمول عکس زیر بهتر توضیح داده فکر کنم.منبع: سایت تند خوانالبته برای محاسبه سرعت مطالعه دوتا راه بسیار ساده تر هم وجود دارهیک اینکه یک مطلب رو توی ورد کپی کنید، و زمان بگیرید و یک دقیقه مطالعه کنید، بعد از یک دقیقه ببینید چند کلمه خوندید، برای اینکار فقط بخشی رو که مطالعه کردید رو انتخاب کنید.( خود برنامه ورد هر قسمت از متن رو انتخاب کنید تعداد کلمات رو مینویسه پایین سمت چپ صفحه)تعداد کلمات انتخاب شده اون پایین ظاهر میشهحالا اون تعداد کلمات میشه سرعت مطالعه شما.راه آخر هم برای کسایی هست که توی خوندن متن اینگلیسی هیچ مشکلی ندارند http://www.myreadspeed.com طبق شنیده ها، سرعت مطالعه از 10 کلمه تا 150 کلمه بر دقیقه خیلی کم هست، از 150 تا 250 متوسط، از 250 تا 500 خوبه. و دیگه بالای 500 -600 دیگه تندخوان خفن محسوب میشه. و مثل اینکه میانگین سرعت مطالعه ما ایرانیا حدودا 150 هست.دیگه این قسمت رو خیلی کش دادیم بریم به ادامه بحث.فارسی را پاس بداریم، چون ما را پاس داشت!یک نکته خیلی امیدوار کننده برای ما فارسی زبان ها و عربی زبان ها(که رسم الخط تقریبا مشابهی داریم) این هست که تعداد حروفی که برای هر کلمه به کار میره نسبت به زبان های دیگره دنیا کمتر هست و این باعث میشه سرعت ما راحت تر بالا بره.زبان عربی  در رتبه چهارم از آخر قرار دارهحالا با دو عامل مهم که باعث کند شدن سرعت ما میشه آشنا میشیم:_ گم و گور شدن بین خطوط، تا حالا شده وقتی رسیدین به آخر خط و میخواید برید اول خط بعدی، اشتباهی  یک خط بالا یا پایین رو میخونید؟ منظور همونه (راستش رو بخواید این عامل خیلی تاثیر زیادی نداره از نظر  من ولی توی اکثر منابع ذکر شده) _ بلند خوانی، لب خوانی، درون خوانی. نمیدونم دقت کردید یا نه اما ما معنی کلمات رو با تصاویرشون متوجه نمیشیم، با صداشون متوجه میشیم، بعضی از ما وقتی یک مطلبی رو میخونیم آروم زمزمه میکنیم، عده دیگری هستن که بدون صدا زمزمه میکنن که بهش میگیم لب خوانی. و در بهترین حالت درون خوانی میکنیم، یعنی کلمات رو توی دلمون میخونیم و اون صدا رو میشنویم(بهش میگن subvocalization) ، و بعد تازه متوجه معنی اون کلمه میشیم. هر سه این کار ها (بلندخوانی و لب و...) ذهن مارو تا حد بسیار زیادی درگیر میکنن و از افزایش سرعت مطالعه ما جلوگیری میکنند. چون ذهن بجای اینکه در یک مرحله کلمه رو ببینه و متوجه معنی بشه در سه مرحله متوجه میشه، یعنی دیدن، تلفظ در ذهن یا دهان و در آخر شنیدن اون صدا. همین الان که مشغول خوندن این مطلب هستید میتونید کمی دقت کنید، احتمالا صدای تو دلتون رو میشنوید که همگام با خوندن تک تک این کلمات میاد. و اگر نمی شنوید باید تبریک بگم! چون شما یک مرحله از همه جلو تر هستید. برای   از بین بردن این صدا هم راهکار هایی هست که در ادامه به خدمت عرضتون میرسونم، یا همچین چیزی...چند راهکار نه چندان ساده برای افزایش سرعت مطالعهگسترش حوزه دید.به یک کلمه خیره بشید، سعی کنید بدون اینکه چشمتون رو حرکت بدید  کلمات اطراف آن کلمه را بخوانید. با گسترش حوزه دید شما میتونید تعداد کلمات بیشتری رو در یک لحظه خیره شدن چشمانتون ببینید(به این خیره شدن توی یک لحظه میگنfixation و به هر پرش از چشمتون روی صفحه به کلمات بعدی میگن saccade) این عکس خوب منظورم رو میرسونهتمرینات زیادی هست برای گسترش حوزه دید،  و اصلی  ترین تمرین همونی هست که اولش گفتم،  سعی کنید به یک کلمه خیره بشید و بدون حرکت دادن چشمتون کلمات کناری رو بخونید. این  عکس ها میتونن کمکتون کنند:سعی کنید با خیره شدن به اون سبزه، حروف اطراف رو بخونید.یکم سخت ترشیکم سخت تر ترشحالا علاوه بر این ها، این رو هم علی الحساب داشته باشید: https://motalesharif.com/گسترش-حوزه-دید-با-۶-تمرین-فوق-العاده/ خط بردن. شاید واقعا بنظر مسخره باشه اما موثره، اینکه هنگام مطالعه انگشتتون رو زیر متنی که میخونید حرکت بدید، عین اول دبستان! این کار باعث میشه که چشم شما توسط انگشتتون هدایت بشه و امکان هرز رفتن رو ازش میگیره. ضمنا یک جایی خوندم بهتره که با انگشت اشاره دست چپتون اینکار رو بکنید، چون دست چپ مربوط به نیمه راست مغزتون هست و ... در  کل خوبه، دلیل علمی از من نخواید :)اینجوری!روش 1-2-3-4. این روش خیلی خوب عمل میکنه بنظرم،  برای خفه کردن اون صدای توی دلمون هست که کلمات رو میخونه. البته برای اول خیلی درک مطلب رو میاره پایین ولی  بعد از چند دقیقه عادت میکنید و اون صدا که توی دلتون بود به طور محسوسی کم میشه. روش اینجوریه که وقتی دارید مطلب رو میخونید توی دلتون از یک تا چهار رو بشمرید: یک دو سه چهار، یک دو سه چهار، یک دو سه چهار... عبارت خوانی، بجای کلمه خوانی. ما عموما تک تک کلمات رو میخونیم تا متوجه متن بشیم ، درصورتی که واقعا نیازی به خوندن تک به تک کلمات نیست. میشه عبارت خوانی کرد، یعنی بجای اینکه هر کلمه رو با یک نگاه خوند، هر دو سه کلمه رو با یک نگاه بخونیم (اینکه چند تا کلمه رو با یک نگاه بخونیم بستگی به حوزه دید هم داره که میشه کم کم افزایش داد تعداد کلمات رو) عکس پایین مثال خوبیه.منبع: سایت همیار ذهنمن از اونجایی که در حال مطالعه هستم در این زمینه احتمالا در آینده اصلاحاتی توی این مطلب صورت بگیره، خیلی تشکر از اینکه تا اینجای مطلب رو همت کردید و خوندید. و در آخر هم منابع :https://motalesharif.comhttp://www.tondkhanionline.irhttp://vojkaniway.comhttps://hawzah.net/fa/Magazine/View/4892/5407/50397/از-سرعت-خود-نکاهیدآشنایی-با-مهارت-های-تندخوانی-در-20-دقیقهhttp://sara-hamidi.com/6-تکنیک-تندخوانی/http://raveshmotalee.irhttp://mahanteymouri.ir/strengthen-eye-muscles-briefing-effective-way-learn/https://abasmanesh.com/fa/https://www.mindtools.com/speedrd.htmlhttps://medium.com/search?q=speed%20readاین پایینی هم یک سایتی هست که میتونید توش با سرعت مطالعه ای که میخواید مطالعه و کنید، تنظیمات ساده ای داره راحت یاد میگیرید:https://www.spreeder.com/app.phpقسمت بعدی این مطلب: https://virgool.io/@riahiamirreza79/%D8%AA%D9%86%D8%AF-%D8%AE%D9%88%D8%A7%D9%86%DB%8C-%D9%85%D8%B1%D8%B6-%D9%88-%D8%AA%D9%86%D8%AF-%D8%AE%D9%88%D8%A7%D9%86%DB%8C-%D9%82%D8%B3%D9%85%D8%AA-%D8%AF%D9%88%D9%85-x633bp2odzkl </description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Wed, 30 May 2018 03:29:05 +0430</pubDate>
            </item>
                    <item>
                <title>روز نگاشت یک فرنگی در ایران</title>
                <link>https://virgool.io/@riahiamirreza79/%D8%B1%D9%88%D8%B2-%D9%86%DA%AF%D8%A7%D8%B4%D8%AA-%DB%8C%DA%A9-%D9%81%D8%B1%D9%86%DA%AF%DB%8C-%D8%AF%D8%B1-%D8%A7%DB%8C%D8%B1%D8%A7%D9%86-m5kzdichjewv</link>
                <description>عکس مرتبط تر یافت نشد! &quot;روز پر دردسری بود، اول که از هتل به سمت سفارت کشورم حرکت کردم متوجه شدم پول های ایرانی ام دارند تمام میشوند و صرافی هم در اطراف نبود. لذا نمیتوانستم از آژانس استفاده کنم و باید با تاکسی و مترو میرفتم. راه افتادم و پس از کمی پیاده روی به خیابان رسیدم و به دلیل کم بودن پول هایم میخواستم در حد توان صرفه جویی نمایم و تا مقصد که مترو باشد را رایگان بروم، در شهر ما برای رایگان تاکسی گرفتن فقط کافیست شستمان را به راننده نشان دهیم، اما من هرچه شستم را به آن ها نشان میدادم آن ها نیز شستشان را به من نشان میدادند،اما راننده ای متفاوت عمل کرد ،بعد از دیدن شست ما ترمز کرد و پنجره داد پایین و در باب عمه و همشیره ما سخنرانی طولانی کرد که ما هیچ نفهمیدیم اما شگفت زده از این همه اطلاعات شدیم، و در آخر به ما امر کرد که &quot;گمشو&quot; و من با توجه به آگاهی ناقصی که در این چند روز نسبت به آن محل پیدا کرده بودم نمیتوانستم به طور ارادی گم شوم ، لذا از ایشان عذر خواهی کرده و علت را جویا شدم اما شخص کمی عصبی بود و عذر خواهی مرا نشنید و رفت. فهمیدم رایگان نمیشود تاکسی گرفت و بلاخره با گفتن مقصد به یک راننده سوار شدم.وقتی به مقصد رسیدیم از او تشکر کرده و جویای هزینه شدم که او فرمود&quot;قابلی ندارد&quot; ما نیز خوشحال از این سواری رایگان پیاده شدیم، اما پس از پیاده شدن و دور شدن ماشین به اندازه کافی از من،راننده با فریاد از پنجره ماشین به من یادآوری نمود که کیف پولم در جیبش جامانده و احتمالا فرصت نبود که پس دهد وگرنه لازم به تذکر نبود.در ادامه راه خیلی به این فکر کردم که چطور کیف پولم بدون خروج از جیب من به جیب ایشان دخول کرده. خوشبختانه یک هزار تومنی در جیبم داشتم برای خرید بلیط مترو . یک بلیط خریدم و مسئول باجه باقی مانده پولم را روی باجه گذاشت، پول ها کمی مرطوب، پاره پوره ولی زیاد بود. اما به دلیل اینکه آن پول ها میتوانست حامل هر نوع بیماری باشد از تماس با آن ها اجتناب ورزیدم.در مترو هر تابلویی بود در ضم واردات جنس قاچاق و دست فروشی بود و هر که بود وارد کننده جنس قاچاق و دست فروش. به من گفته بودند ایستگاه دکتر شریعتی بود پیاده شوم، و متذکر شدند برای اینکه محیط برای من غریب است و زبان اطراف بیگانه، لازم به گشتن به دنبال تابلوی اینگلیسی نیست کافیست به صدای بلندگوی قطار توجه بنمایم که در هر ایستگاه نام آن ایستگاه را میگوید. اما گویا بلندگوی قطار خراب بوده و ما تا ایستگاهی رفتیم به نام امم اسم ایستگاه یادم نیست اما مضمونش مرد جوانی که از راه قصابی روزگار میگذارند بود. از فردی پرسیدم &quot;وِر ایز دی داکتر شریعتیز اِستیشن&quot; و او با&quot;آیم فاین تنکیو &quot; جوابم را داد. به دلیل اینکه مدت زیادی بود در قطار بودم حدودا60 دقیقه، و به من گفته شده بود مسیرت در مترو 5 دقیقه طول میکشد کمی شک کرده و از قطار پیاده شده و پس از گشتن زیاد دانشجویی را یافتم که به زبان ما از ما مسلط تر بود . و پس از پرسش و پاسخی دریافتم که ایستگاه را خیلی قبل رد کرده. به ناچار به آن طرف ایستگاه رفته و سوار قطار های آن طرف شده ولی این بار برای اطمینان بیشتر هر بار که به ایستگاهی میرسیدیم از مردی که زبان خارج بلد بود نام آن ایستگاه را میپرسیدم و در اواخر راه او علت ریختن موهایش را پرسش های مکرر من میدانست اما من از قبل از شروع مکالمه با وی ،دیده بودم که موهایش ریخته و فکر نمیکنم پرسش یک سوال به دفعات موجب کچلی شود.به ایستگاه شریعتی که رسیدم. از ایستگاه بیرون رفتم و تا سفارت را پیاده طی کرده و پس از رسیدن به سفارت و بار ها زنگ در را زدن و مدتی پشت در منتظر ماندن و زنگ زدن و پرسیدن مطلع شدم که امروز روز جمعه یا فرایدی هست که برای مردم ایران روز تعطیل میباشد و همان لحظه با پرسیدن آدرس نزدیک ترین صرافی به آنجا رفته و پس مواجه شدن با در بسته آن نا امید شدم و سعی در پیدا کردن راننده ای که دلار قبول کند کردم. این کار بسیار سخت بود چون در میان راننده ها همه زبان مارا بلد نبوده و من باید خیلی میگشتم تا راننده ای را پیدا کنم که هم انگلیش بلد باشد و هم دلار قبول میکرد. و در آخر پیدا کردم .من که آدرس هتل مان را بلد نبودم و با نشان دادن کارت هتل به راننده قرار شد در ازای 15 دلار مارا به هتل برساند.متاسفانه حین برگشت هوا داشت تاریک میشد و ما با ترافیک بسیار سنگینی در یک خیابانی که اسمش را نمیدانم رو به رو شدیم.شخص راننده که بسیار با شخصیت و محترم بود به ما توصیه کرد که اگر ادامه مسیر را پیاده و کمی اش را با تاکسی بروم زودتر میرسم به مقصد و بجای 15 دلار از ما 8 دلار گرفت و مارا پیاده نمود. و به ما راهنمایی کرد که برویم در خیابانی به نام ولی العصر و کوچه ای بنام فرشید راه دارد به خیابانی که هتل ما در آنجاست. اما متاسفانه راننده فراموش کرد که به من تذکر دهد که خیابان ولی عصر بزرگ ترین خیابان میدل اِست (خاور وسط) است و پیدا کردن یک کوچه در این خیابان کاری محال است. و پس از 1ساعتی پیاده روی از شخصی که دست و پار شکسته زبان مارا بلد بود پرسیدم کوچه فرشید چقدر دیگه راه است، اما او گفت این خیابان 1000تا کوچه و از من مقصدم را پرسید، من هم کارت هتل را نشانش دادم، خوشبختانه نزدیک بودم ، بعد از 10 دقیقه پیاده روی رسیدم به هتل. و طبق عادت دوشی گرفته، شام ساده ای خورده، قهوه ای نوشیده و خوابیدم تا خستگی این روز سخت و بیهوده از تنم به در آید.&quot;    </description>
                <category>امیررضا ریاحی</category>
                <author>امیررضا ریاحی</author>
                <pubDate>Mon, 19 Mar 2018 23:40:37 +0330</pubDate>
            </item>
            </channel>
</rss>