Multithreading: Cara Menggunakan Kelas Sinkronisasi MFC
Menyinkronkan akses sumber daya antar alur adalah masalah umum saat menulis aplikasi multithread. Memiliki dua utas atau lebih secara bersamaan mengakses data yang sama dapat menyebabkan hasil yang tidak diinginkan dan tidak dapat diprediksi. Misalnya, satu utas dapat memperbarui konten struktur sementara utas lain membaca konten struktur yang sama. Tidak diketahui data apa yang akan diterima utas baca: data lama, data yang baru ditulis, atau mungkin campuran keduanya. MFC menyediakan sejumlah kelas akses sinkronisasi dan sinkronisasi untuk membantu memecahkan masalah ini. Topik ini menjelaskan kelas yang tersedia dan cara menggunakannya untuk membuat kelas aman utas dalam aplikasi multithread yang khas.
Aplikasi multithread khas memiliki kelas yang mewakili sumber daya yang akan dibagikan di antara utas. Kelas yang dirancang dengan benar dan sepenuhnya aman tidak mengharuskan Anda untuk memanggil fungsi sinkronisasi apa pun. Semuanya ditangani secara internal ke kelas, memungkinkan Anda untuk berkonsentrasi pada cara terbaik menggunakan kelas , bukan tentang bagaimana mungkin rusak. Teknik yang efektif untuk membuat kelas yang sepenuhnya aman untuk alur adalah menggabungkan kelas sinkronisasi ke dalam kelas sumber daya. Menggabungkan kelas sinkronisasi ke dalam kelas bersama adalah proses yang mudah.
Sebagai contoh, ambil aplikasi yang mempertahankan daftar akun yang ditautkan. Aplikasi ini memungkinkan hingga tiga akun untuk diperiksa di jendela terpisah, tetapi hanya satu yang dapat diperbarui pada waktu tertentu. Saat akun diperbarui, data yang diperbarui dikirim melalui jaringan ke arsip data.
Contoh aplikasi ini menggunakan ketiga jenis kelas sinkronisasi. Karena memungkinkan hingga tiga akun diperiksa pada satu waktu, akun tersebut menggunakan CSemaphore untuk membatasi akses ke tiga objek tampilan. Ketika upaya untuk melihat akun keempat terjadi, aplikasi menunggu hingga salah satu dari tiga jendela pertama ditutup atau gagal. Ketika akun diperbarui, aplikasi menggunakan CCriticalSection untuk memastikan bahwa hanya satu akun yang diperbarui pada satu waktu. Setelah pembaruan berhasil, ia memberi sinyal CEvent, yang merilis utas yang menunggu peristiwa disinyalir. Utas ini mengirimkan data baru ke arsip data.
Merancang Kelas Thread-Safe
Untuk membuat kelas sepenuhnya aman, pertama-tama tambahkan kelas sinkronisasi yang sesuai ke kelas bersama sebagai anggota data. Dalam contoh manajemen akun sebelumnya, CSemaphore
anggota data akan ditambahkan ke kelas tampilan, CCriticalSection
anggota data akan ditambahkan ke kelas daftar tertaut, dan CEvent
anggota data akan ditambahkan ke kelas penyimpanan data.
Selanjutnya, tambahkan panggilan sinkronisasi ke semua fungsi anggota yang memodifikasi data di kelas atau mengakses sumber daya terkontrol. Dalam setiap fungsi, Anda harus membuat objek CSingleLock atau CMultiLock dan memanggil fungsi objek tersebut Lock
. Ketika objek kunci keluar dari cakupan dan dihancurkan, destruktor objek memanggil Unlock
Anda, melepaskan sumber daya. Tentu saja, Anda dapat menelepon Unlock
langsung jika Anda mau.
Merancang kelas thread-safe Anda dengan cara ini memungkinkannya untuk digunakan dalam aplikasi multithreaded dengan mudah sebagai kelas non-thread-safe, tetapi dengan tingkat keamanan yang lebih tinggi. Merangkum objek sinkronisasi dan objek akses sinkronisasi ke kelas sumber daya memberikan semua manfaat dari pemrograman yang sepenuhnya aman tanpa kelemahan mempertahankan kode sinkronisasi.
Contoh kode berikut menunjukkan metode ini dengan menggunakan anggota data, m_CritSection
(dari jenis CCriticalSection
), dinyatakan dalam kelas sumber daya bersama dan CSingleLock
objek. Sinkronisasi sumber daya bersama (berasal dari CWinThread
) dicoba dengan membuat CSingleLock
objek menggunakan alamat m_CritSection
objek. Upaya dilakukan untuk mengunci sumber daya dan, ketika diperoleh, pekerjaan dilakukan pada objek bersama. Setelah pekerjaan selesai, sumber daya dibuka kuncinya dengan panggilan ke Unlock
.
CSingleLock singleLock(&m_CritSection);
singleLock.Lock();
// resource locked
//.usage of shared resource...
singleLock.Unlock();
Catatan
CCriticalSection
, tidak seperti kelas sinkronisasi MFC lainnya, tidak memiliki opsi permintaan penguncian waktu. Periode tunggu untuk utas menjadi gratis tidak terbatas.
Kelemahan dari pendekatan ini adalah bahwa kelas akan sedikit lebih lambat daripada kelas yang sama tanpa objek sinkronisasi ditambahkan. Selain itu, jika ada kemungkinan lebih dari satu utas dapat menghapus objek, pendekatan gabungan mungkin tidak selalu berfungsi. Dalam situasi ini, lebih baik mempertahankan objek sinkronisasi terpisah.
Untuk informasi tentang menentukan kelas sinkronisasi mana yang akan digunakan dalam situasi yang berbeda, lihat Multithreading: Kapan Menggunakan Kelas Sinkronisasi. Untuk informasi selengkapnya tentang sinkronisasi, lihat Sinkronisasi di Windows SDK. Untuk informasi selengkapnya tentang dukungan multithreading di MFC, lihat Multithreading dengan C++ dan MFC.