การอ่านสกปรกจากหน่วยความจำเป็นไปได้หรือไม่เมื่อใช้งานแบบมัลติเธรด?

ในกรณีนี้ ฉันกำหนด dirty read ว่าเป็นการอ่านจากหน่วยความจำ เมื่อเธรดอื่นกำลังเขียนถึงเธรดอื่น

ดังนั้นหากเธรด #1 เขียน 100 ไปยังตัวแปรที่เธรด #2 สามารถมองเห็นได้ นั่นจะเขียน 50 ไปยังตัวแปรเดียวกัน โดยที่ทั้งสองเธรดทำในลักษณะวนซ้ำ

เป็นไปได้ไหมที่จะอ่านตัวแปรแล้วได้ตัวเลขที่ไม่ใช่ 50 หรือ 100? ไม่มีการล็อค ฯลฯ สำหรับการซิงค์

รายละเอียดเพิ่มเติมเกี่ยวกับการตั้งค่าของฉัน: Intel i3 CPU ฉันกำลังเขียนโปรแกรมใน C#

ด้านล่างนี้เป็นตัวอย่างของสิ่งที่ฉันหมายถึง:

using System;
using System.Collections.Generic;
using System.Threading;

namespace Threading001
{
    class Program
    {
        static void Main(string[] args)
        {
            long min = long.MinValue;
            long max = long.MaxValue;
            object number = max;

            new Thread(() =>
            {
                long current2 = (long)number;
                if (current2 != min && current2 != max)
                {
                    Console.WriteLine("Unexpected number from thread 2: {0}.", current2);
                }
                number = min;
            }).Start();

            while (true)
            {
                long current = (long)number;
                if (current != min && current != max)
                {
                    Console.WriteLine("Unexpected number from thread 1: {0}.", current);
                }
                number = max;
            }

        }
    }
}

ฉันสร้าง number วัตถุเพื่อให้หน่วยความจำได้รับการจัดสรรบนฮีป ไม่ใช่สแต็กเพื่อพยายามเพิ่มเวลาแฝงในการเข้าถึงหน่วยความจำ การแคชซีพียูอาจจะหยุดสิ่งนั้นต่อไป


person user1515024    schedule 31.12.2013    source แหล่งที่มา
comment
คุณไม่ได้ให้ข้อมูลบ่งชี้ว่าคุณกำลังใช้ CPU, ภาษา หรือประเภทข้อมูลใด... ซึ่งทำให้ไม่สามารถพูดได้จริงๆ   -  person Jon Skeet    schedule 31.12.2013
comment
ขึ้นอยู่กับสถาปัตยกรรมและขนาด/การจัดแนวของการเขียน คุณอยู่บนแพลตฟอร์มไหน?   -  person Cory Nelson    schedule 31.12.2013


คำตอบ (4)


คุณกำลังพยายามพึ่งพาหลายสิ่งที่แตกต่างกันที่นี่

ประการแรก มีเรื่องของอะตอมมิกซิตี ECMA-335 ระบุว่า:

CLI ที่สอดคล้องจะต้องรับประกันว่าการเข้าถึงการอ่านและเขียนไปยังตำแหน่งหน่วยความจำที่จัดตำแหน่งอย่างถูกต้องซึ่งไม่ใหญ่กว่าขนาดคำดั้งเดิม (ขนาดของประเภท Native int) เป็นแบบอะตอมมิก (ดู§I.12.6.2) เมื่อการเข้าถึงการเขียนทั้งหมดไปยังตำแหน่งนั้น ขนาดเดียวกัน การเขียนแบบอะตอมมิกจะต้องไม่เปลี่ยนแปลงบิตอื่นใดนอกจากที่เขียน เว้นแต่จะใช้การควบคุมเลย์เอาต์ที่ชัดเจน (ดูพาร์ติชัน II (การควบคุมเลย์เอาต์อินสแตนซ์)) เพื่อเปลี่ยนพฤติกรรมเริ่มต้น องค์ประกอบข้อมูลที่มีขนาดไม่เกินขนาดคำปกติ (ขนาดของ int ดั้งเดิม) จะต้องถูกจัดเรียงอย่างเหมาะสม การอ้างอิงออบเจ็กต์จะต้องได้รับการปฏิบัติเหมือนกับว่าถูกจัดเก็บไว้ในขนาดคำดั้งเดิม

ดังนั้นสำหรับจำนวนเต็ม 32 บิต คุณก็สบายดีเสมอ - และสำหรับจำนวนเต็ม 64 บิต คุณก็สบายดีถ้าคุณใช้ CLR 64 บิต... สมมติว่าตัวแปรของคุณอยู่ในแนวเดียวกัน ซึ่งโดยปกติแล้วพวกมันจะเป็นเช่นนั้น .

อย่างไรก็ตาม คุณมีส่วนเกี่ยวข้องกับการชกมวยด้วย - ฉันไม่คิดว่าจะสร้างปัญหาใดๆ ที่นี่ แต่หมายความว่าคุณกำลังเผชิญกับการมองเห็นของการเขียนหลายรายการ: รายการหนึ่งสำหรับตัวแปร number และอีกอันสำหรับข้อมูลภายในกล่อง ด้วยการใช้ .NET ฉันเชื่อว่ายังคงปลอดภัยเนื่องจากหน่วยความจำที่แข็งแกร่งกว่ารับประกันว่าจะมีให้ - ฉันไม่ต้องการรับประกันอย่างแน่นอนว่าจะปลอดภัยภายในโมเดลหน่วยความจำ ECMA

สุดท้ายนี้ เป็นเรื่องของการเขียนว่าจะ มองเห็นได้ หรือไม่ ซึ่งอยู่นอกเหนือความเป็นอะตอมมิก หากเธรด T1 เปลี่ยนค่า int จาก 0 เป็น 100 ดังนั้นเธรด T2 จะอ่านมัน atomicity รับประกันว่า T2 จะเห็น 0 หรือ 100 ไม่มีรูปแบบบิตอื่นใด - แต่โดยปกติจะต้องมี อุปสรรคหน่วยความจำบางประเภท< /em> เกี่ยวข้องเพื่อรับประกันว่า T2 จะเห็นค่าใหม่จริง ๆ แทนที่จะเป็นค่าเก่า นี่เป็นพื้นที่ที่ซับซ้อนมาก - หากคุณต้องการทราบข้อมูลเพิ่มเติม ฉันขอแนะนำให้คุณเริ่มต้นด้วย บล็อกโพสต์ของ Joe Duffy ในปี 2007 และทำงานจากที่นั่น

โปรดทราบว่า min, max และ number จะยังอยู่บนฮีป เนื่องจากถูก จับ โดยนิพจน์แลมบ์ดาของคุณ... แม้ว่าสแต็ก/ฮีปจะเป็นรายละเอียดการใช้งานก็ตาม

person Jon Skeet    schedule 31.12.2013

ขึ้นอยู่กับว่าตัวแปรคืออะไร (และตัวประมวลผลใด ฯลฯ ฯลฯ) แต่โดยทั่วไปแล้ว:
ใช่ การอ่านสกปรกเป็นไปได้

person deviantfan    schedule 31.12.2013

ฉันไม่คุ้นเคยกับรายละเอียดของ CPU เฉพาะของคุณ แต่โดยทั่วไปแล้วจะขึ้นอยู่กับว่าการอ่าน/เขียนเป็นแบบอะตอมมิกหรือไม่ ซึ่งจะขึ้นอยู่กับสถาปัตยกรรมและวิธีการจัดเก็บตัวแปร

หากตัวแปรมีขนาดใหญ่กว่าขนาดคำของ CPU ตัวแปรนั้นอาจไม่เป็นแบบอะตอมมิก

ซีพียูสมัยใหม่อาจรับประกันการเข้าถึงแบบอะตอมมิกไปยังที่อยู่หน่วยความจำที่จัดตำแหน่ง หากจำเป็นต้องพิจารณาเพิ่มเติมหากไม่มีการรองรับ HW สำหรับการเข้าถึงหน่วยความจำที่ไม่ตรงแนว หากซอฟต์แวร์จัดการการเข้าถึงหน่วยความจำที่ไม่ตรงแนว การอ่านหรือเขียนจะไม่เป็นแบบอะตอมมิก: โหลด/จัดเก็บหนึ่งครั้งอาจนำไปสู่การดำเนินการจริงสองครั้ง ตัวอย่างหนึ่งคือ PowerPC/Linux โดยที่เคอร์เนลจัดการการเข้าถึงหน่วยความจำที่ไม่ตรงแนวในตัวจัดการข้อยกเว้น

person tristan    schedule 31.12.2013

ทั้งหมดนี้เกี่ยวกับความปลอดภัยของเธรดหรือไม่ ขึ้นอยู่กับประเภทข้อมูลของตัวแปรที่คุณต้องการอ่าน บางชนิดเช่น long, int, byte ฯลฯ เป็นเธรดที่ปลอดภัย และคุณสามารถอ่านและเขียนพวกมันได้หลายเธรด

คุณสามารถหาข้อมูลเพิ่มเติมได้ที่นี่

http://msdn.microsoft.com/en-us/library/dd997305(v=vs.110).aspx

ประเภทข้อมูลดั้งเดิมใน c# atomic (เธรดปลอดภัย) หรือไม่

เธรดที่ปลอดภัย (C#) คืออะไร (สตริง, อาร์เรย์, ... ?)

person Jack Gajanan    schedule 31.12.2013