Motivasinya
dimulai dari bersentuhan dengan model pemrograman multi-thread (proses), dan yang saya pelajari adalah primitif sinkronisasi yang terkait dengan semaphore (Semaphore). Saya tidak tahu mengapa tidak ada hal yang sesuai di .Net Framework. Hal yang buruk adalah saya menggunakannya untuk mengimplementasikan banyak kode C++ yang telah teruji waktu. Untuk mencegah para martir revolusioner meminum obat dan mengeluarkan darah dengan sia-sia, saya sendiri harus melahirkannya.
Apa itu semaphore?
Jika Anda sudah memahami konsep semaphore, silakan lewati bagian ini.
Semaphore adalah fasilitas yang digunakan dalam lingkungan multi-thread. Ia bertanggung jawab untuk mengoordinasikan berbagai thread untuk memastikan bahwa mereka dapat menggunakan sumber daya publik dengan benar dan wajar.
Mari kita lihat cara kerja tempat parkir. Demi kesederhanaan, asumsikan bahwa tempat parkir hanya mempunyai tiga tempat parkir, dan ketiga tempat parkir tersebut pada awalnya kosong. Ini terjadi jika lima mobil datang pada waktu yang sama, dan penjaga gerbang mengizinkan tiga mobil masuk tanpa halangan, lalu meletakkan blok mobil, mobil yang tersisa harus menunggu di pintu masuk, dan mobil berikutnya juga harus menunggu di pintu masuk. pintu masuk. Pada saat ini, sebuah mobil meninggalkan tempat parkir. Setelah penjaga gerbang mengetahuinya, dia membuka pembatas mobil dan memasukkan satu mobil. Jika ada dua mobil lagi, dia dapat memasukkan dua mobil lagi, dan seterusnya.
Dalam sistem parkir ini, tempat parkir merupakan sumber daya publik, setiap mobil ibarat benang, dan penjaga gerbang berperan sebagai semaphore.
Selanjutnya ciri-ciri semaphore adalah sebagai berikut: semaphore adalah bilangan bulat non-negatif (jumlah tempat parkir), dan semua thread (kendaraan) yang melewatinya akan mengurangi bilangan bulat tersebut satu (melewatinya tentu saja menggunakan sumber daya ). Ketika nilai integer berada pada nol, semua thread yang mencoba meneruskannya akan berada dalam status menunggu. Kami mendefinisikan dua operasi pada semaphore: Tunggu dan Lepaskan. Ketika sebuah thread memanggil operasi Tunggu, thread tersebut akan meneruskan dan kemudian mengurangi semaphore sebanyak satu, atau menunggu hingga semaphore lebih besar dari satu atau waktu habis. Rilis sebenarnya melakukan operasi penambahan pada semafor, yang sesuai dengan kendaraan yang meninggalkan tempat parkir. Alasan mengapa operasi ini disebut "lepaskan" adalah karena operasi penambahan sebenarnya melepaskan sumber daya yang dijaga oleh semafor.
menyelesaikan
Seperti kita ketahui bersama, fasilitas sinkronisasi thread yang disediakan pada class library .Net Framework antara lain:
Monitor, AutoResetEvent, ManualResetEvent, Mutex, ReadWriteLock dan InterLock. Diantaranya, AutoResetEvent, ManualResetEvent, dan Mutex berasal dari WaitHandler, dan mereka sebenarnya merangkum objek kernel yang disediakan oleh sistem operasi. Lainnya harus asli dari mesin virtual .Net. Tentunya fasilitas dari objek kernel sistem operasi kurang efisien untuk digunakan. Namun, efisiensi bukanlah masalah yang harus kita pertimbangkan di sini. Kita akan menggunakan dua Monitor dan objek ManualResetEvent untuk mensimulasikan semaphore.
Kodenya adalah sebagai berikut:
Semafor kelas publik
{
pribadi ManualResetEvent waitEvent = new ManualResetEvent(false);
objek pribadi syncObjWait = objek baru();
private int maxCount = 1; //Jumlah sumber daya maksimum
private int currentCount = 0; //Jumlah resource
public Semaphore()
{
}
Semafor publik( int maxCount )
{
this.maxCount = maxCount;
}
bool publik Tunggu()
{
lock( syncObjWait ) //Hanya satu thread yang dapat memasukkan kode berikut
{
bool waitResult = this.waitEvent.WaitOne(); //Jumlah sumber daya yang menunggu di sini lebih dari nol
jika (tunggu Hasil)
{
kunci (ini)
{
jika(Jumlah saat ini > 0 )
{
Jumlah saat ini--;
jika(Jumlah saat ini == 0 )
{
ini.waitEvent.Reset();
}
}
kalau tidak
{
System.Diagnostics.Debug.Assert( false, "Semaphore tidak mengizinkan penghitungan saat ini < 0" );
}
}
}
kembali tungguHasil;
}
}
/**//// <ringkasan>
/// Tunggu operasi yang memungkinkan batas waktu kembali
/// </ringkasan>
/// <nama param="millisecondsTimeout"></param>
/// <pengembalian></pengembalian>
bool publik Tunggu (int milidetikWaktu habis)
{
lock( syncObjWait ) // Monitor memastikan bahwa kode kelas cakupan berada dalam bagian kritis
{
bool waitResult = this.waitEvent.WaitOne(milidetikTimeout,false);
jika (tunggu Hasil)
{
kunci (ini)
{
jika(Jumlah saat ini > 0 )
{
Jumlah saat ini--;
jika(Jumlah saat ini == 0 )
{
ini.waitEvent.Reset();
}
}
kalau tidak
{
System.Diagnostics.Debug.Assert( false, "Semaphore tidak mengizinkan penghitungan saat ini < 0" );
}
}
}
kembali tungguHasil;
}
}
Rilis bool publik()
{
lock( this ) // Monitor memastikan bahwa kode kelas cakupan berada dalam bagian kritis
{
Jumlah saat ini++;
jika(Jumlah saat ini > ini.maxCount )
{
currentCount = ini.maxCount;
kembali salah;
}
this.waitEvent.Set(); //Izinkan thread memanggil Tunggu untuk masuk
}
kembali benar;
}
}