Apakah pembacaan kotor dari memori dapat dilakukan saat multi-threading?

Dalam hal ini, saya mendefinisikan bacaan kotor sebagai membaca dari memori ketika sedang ditulis oleh thread lain.

Jadi jika thread #1 menulis 100 ke variabel yang juga dapat dilihat oleh thread #2, maka thread #2 akan menulis 50 ke variabel yang sama, di mana kedua thread melakukannya dalam satu lingkaran.

Apakah mungkin membaca variabel dan mendapatkan angka bukan 50 atau 100? Tidak menggunakan kunci dll untuk sinkronisasi.

Lebih detail tentang pengaturan saya: CPU Intel i3, saya memprogram dalam C#.

Di bawah ini adalah contoh yang saya maksud:

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;
            }

        }
    }
}

Saya menjadikan number sebagai objek sehingga memori dialokasikan di heap dan bukan di stack untuk mencoba dan meningkatkan waktu latensi akses memori. Meskipun caching cpu mungkin akan menghentikannya.


person user1515024    schedule 31.12.2013    source sumber
comment
Anda tidak memberi kami indikasi tentang CPU, bahasa, atau tipe data apa yang Anda gunakan... sehingga sulit untuk mengatakannya, sungguh.   -  person Jon Skeet    schedule 31.12.2013
comment
Tergantung pada arsitektur dan ukuran/penyelarasan penulisan. Anda berada di platform apa?   -  person Cory Nelson    schedule 31.12.2013


Jawaban (4)


Anda sebenarnya mencoba mengandalkan beberapa hal berbeda di sini.

Pertama, ada masalah atomisitas. ECMA-335 menyatakan:

CLI yang sesuai harus menjamin bahwa akses baca dan tulis ke lokasi memori yang disejajarkan dengan benar tidak lebih besar dari ukuran kata asli (ukuran tipe int asli) bersifat atomik (lihat §I.12.6.2) ketika semua akses tulis ke suatu lokasi adalah ukuran yang sama. Penulisan atom tidak boleh mengubah bit apa pun selain yang tertulis. Kecuali kontrol tata letak eksplisit (lihat Partisi II (Tata Letak Instance Pengendalian)) digunakan untuk mengubah perilaku default, elemen data yang tidak lebih besar dari ukuran kata alami (ukuran int asli) harus disejajarkan dengan benar. Referensi objek harus diperlakukan seolah-olah disimpan dalam ukuran kata asli.

Jadi untuk bilangan bulat 32-bit, Anda selalu baik-baik saja - dan untuk bilangan bulat 64-bit, Anda baik-baik saja jika Anda menjalankan CLR 64-bit... dengan asumsi variabel Anda selaras, dan biasanya memang begitu .

Namun, Anda juga melibatkan tinju - menurut saya hal itu tidak berpikir akan menyebabkan masalah apa pun di sini, namun itu berarti Anda berurusan dengan visibilitas beberapa penulisan: satu untuk variabel number itu sendiri, dan satu untuk data di dalam kotak. Dengan implementasi .NET, saya yakin itu masih aman karena jaminan memori yang lebih kuat yang diberikannya - Saya tidak ingin menjamin sepenuhnya bahwa itu aman dalam model memori ECMA.

Terakhir, ada masalah apakah suatu tulisan terlihat atau tidak, yang berada di luar jangkauan atomisitas. Jika thread T1 mengubah nilai int dari 0 menjadi 100, lalu thread T2 membacanya, atomisitas menjamin bahwa T2 akan melihat 0 atau 100, tidak pernah melihat pola bit lain - namun biasanya harus ada semacam penghalang memori< /em> terlibat untuk menjamin bahwa T2 akan benar-benar melihat nilai baru dan bukan nilai lama. Ini adalah area yang sangat kompleks - jika Anda ingin mengetahui lebih banyak, saya sarankan Anda memulai dengan entri blog Joe Duffy tahun 2007 dan bekerja dari sana.

Perhatikan bahwa min, max dan number akan tetap ada di heap, karena mereka telah ditangkap oleh ekspresi lambda Anda... meskipun stack/heap adalah detail implementasi.

person Jon Skeet    schedule 31.12.2013

Tergantung variabelnya (dan prosesor apa, dll.), tetapi secara umum:
Ya, pembacaan kotor mungkin terjadi.

person deviantfan    schedule 31.12.2013

Saya tidak mengetahui detail CPU spesifik Anda tetapi secara umum hal ini bergantung pada apakah READ/WRITE bersifat atomik atau tidak, yang pada gilirannya bergantung pada arsitektur dan cara variabel disimpan.

Jika variabel memiliki ukuran lebih besar dari ukuran kata CPU, variabel tersebut mungkin bukan atomik.

CPU modern dapat menjamin akses atom ke alamat memori yang selaras; jika perlu pertimbangan lebih lanjut jika tidak memiliki dukungan HW untuk akses memori yang tidak selaras. Jika akses memori yang tidak selaras ditangani oleh perangkat lunak, pembacaan atau penulisan tidak akan bersifat atomik: satu pemuatan/penyimpanan sebenarnya dapat menyebabkan dua operasi. Salah satu contohnya adalah PowerPC/Linux di mana kernel menangani akses memori yang tidak selaras dalam pengendali pengecualian.

person tristan    schedule 31.12.2013

ini semua tentang thread aman atau tidak itu tergantung pada tipe data variabel yang ingin Anda baca, beberapa tipe seperti long, int, byte dll aman untuk thread dan Anda dapat membaca dan menulisnya di banyak thread.

Anda dapat menemukan informasi lebih lanjut di sini

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

Apakah tipe data primitif dalam c# atom (thread aman)?

Apa itu thread safe (C#)? (String, array, ... ?)

person Jack Gajanan    schedule 31.12.2013