Ketika menulis multi-threaded aplikasi, salah satu masalah yang paling umum dialami adalah kondisi ras.
Pertanyaan saya kepada masyarakat adalah:
Apa kondisi balapan? Bagaimana anda mendeteksi mereka? Bagaimana anda menangani mereka? Akhirnya, bagaimana anda mencegah mereka dari terjadi?
Perlombaan kondisi yang terjadi ketika dua atau lebih benang yang dapat mengakses data bersama dan mereka mencoba untuk mengubah itu pada waktu yang sama. Karena benang algoritma penjadwalan dapat swap antara benang pada setiap saat, anda don't tahu di mana benang akan mencoba untuk mengakses data bersama. Oleh karena itu, hasil dari perubahan pada data tergantung pada benang algoritma penjadwalan, yaitu benang "racing" untuk mengakses/mengubah data.
Permasalahan yang sering terjadi ketika salah satu thread tidak "check-kemudian-undang-undang" (misalnya "periksa" jika nilai X, maka "undang-undang" untuk melakukan sesuatu yang tergantung pada nilai X) dan thread lain melakukan sesuatu untuk nilai di antara "periksa" dan "undang-undang". E. g:
if (x == 5) // The "Check"
{
y = x * 2; // The "Act"
// If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
// y will not be equal to 10.
}
Intinya, y bisa 10, atau bisa apa saja, tergantung pada apakah thread lain berubah x di antara cek dan bertindak. Anda tidak punya cara untuk mengetahui.
Dalam rangka untuk mencegah race conditions terjadi, anda biasanya akan menempatkan mengunci seluruh data bersama untuk memastikan hanya satu thread yang dapat mengakses data pada satu waktu. Ini akan berarti sesuatu seperti ini:
// Obtain lock for x
if (x == 5)
{
y = x * 2; // Now, nothing can change x until the lock is released.
// Therefore y = 10
}
// release lock for x
"kondisi balapan" ada ketika multithreaded (atau paralel) kode yang akan mengakses sumber daya bersama bisa melakukannya dengan cara seperti untuk menyebabkan hasil yang tak terduga.
Ambil contoh ini:
for ( int i = 0; i < 10000000; i++ )
{
x = x + 1;
}
Jika anda memiliki 5 benang mengeksekusi kode ini sekaligus, nilai x TIDAK AKAN berakhir menjadi 50,000,000. Hal ini sebenarnya akan bervariasi dengan masing-masing berjalan.
Ini adalah karena, dalam rangka untuk setiap thread untuk kenaikan nilai x, mereka harus melakukan hal berikut: (sederhana, jelas)
Mengambil nilai dari x Tambahkan 1 untuk nilai ini Toko ini nilai x
Setiap thread dapat pada setiap langkah dalam proses ini setiap saat, dan mereka dapat menginjak satu sama lain ketika bersama sumber daya yang terlibat. Keadaan x dapat diubah oleh thread lain selama waktu antara x sedang membaca dan ketika itu ditulis kembali.
Let's mengatakan thread mengambil nilai dari x, tapi belum't disimpan itu belum. Thread lain juga dapat mengambil sama nilai x (karena tidak ada benang yang telah berubah itu belum) dan kemudian mereka akan menyimpan sama nilai (x+1) kembali dalam x!
Contoh:
Thread 1: membaca x, nilai 7 Thread 1: menambahkan 1 ke x, nilai sekarang 8 Thread 2: membaca x, nilai 7 Thread 1: toko 8 di x Thread 2: menambahkan 1 ke x, nilai sekarang 8 Thread 2: toko 8 di x
Perlombaan kondisi ini dapat dihindari dengan menggunakan semacam mengunci mekanisme sebelum kode yang mengakses sumber daya bersama:
for ( int i = 0; i < 10000000; i++ )
{
//lock x
x = x + 1;
//unlock x
}
di Sini, jawaban yang keluar sebagai 50,000,000 setiap waktu.
Untuk informasi lebih lanjut tentang penguncian, pencarian untuk: mutex, semaphore, bagian penting, sumber daya bersama.
Apa adalah Kondisi Balapan?
Anda berencana untuk pergi untuk sebuah film di 5 pm. Anda menanyakan tentang ketersediaan tiket pada pukul 4 sore. Perwakilan mengatakan bahwa mereka tersedia. Anda rileks dan mencapai jendela tiket 5 menit sebelum acara. I'm yakin anda bisa menebak apa yang terjadi:'s full house. Masalahnya di sini adalah dalam durasi antara cek dan tindakan. Anda bertanya pada 4 dan bertindak pada 5. Sementara itu, orang lain meraih tiket. Yang's kondisi balapan - khusus "check-kemudian-undang-undang" skenario kondisi ras.
Bagaimana anda mendeteksi mereka?
Agama code review, multi-threaded unit tes. Tidak ada jalan pintas. Ada beberapa Eclipse plugin muncul pada ini, tapi tidak ada yang belum stabil.
Bagaimana anda menangani dan mencegah mereka?
Hal terbaik yang akan membuat efek samping gratis dan bernegara fungsi, penggunaan immutables sebanyak mungkin. Tapi itu tidak selalu mungkin. Jadi menggunakan java.util.bersamaan.atom, bersamaan struktur data, sinkronisasi yang tepat, dan aktor berdasarkan concurrency akan membantu.
Sumber daya terbaik untuk concurrency adalah JCIP. Anda juga bisa mendapatkan lebih banyak detail pada penjelasan di atas di sini.
Ada perbedaan teknis antara kondisi ras dan ras data. Kebanyakan jawaban tampaknya membuat asumsi bahwa istilah-istilah ini adalah sama, tetapi mereka tidak.
Data ras terjadi ketika 2 instruksi mengakses lokasi memori, setidaknya salah satu dari ini mengakses adalah menulis dan tidak ada terjadi sebelum memesan di antaranya mengakses. Sekarang apa yang merupakan terjadi sebelum memesan tunduk pada banyak perdebatan, tapi secara umum ulock-kunci pasang pada kunci yang sama variabel dan menunggu-sinyal pasangan pada kondisi yang sama variabel mendorong terjadi-sebelum order.
Kondisi balapan adalah kesalahan semantik. Ini adalah cacat yang terjadi pada waktu atau urutan peristiwa yang menyebabkan kesalahan program perilaku.
Race banyak kondisi yang dapat (dan sebenarnya) yang disebabkan oleh data balapan, tapi ini tidak diperlukan. Sebagai soal fakta, data, ras dan ras kondisi yang tidak diperlukan, atau kondisi yang cukup untuk satu sama lain. Ini posting blog juga menjelaskan perbedaan sangat baik, dengan sederhana transaksi bank misalnya. Berikut ini adalah sederhana example yang menjelaskan perbedaan.
Sekarang bahwa kita dipaku terminologi, mari kita coba untuk menjawab pertanyaan awal.
Mengingat bahwa ras kondisi semantik bug, umumnya tidak ada cara untuk mendeteksi mereka. Hal ini karena tidak ada cara untuk memiliki otomatis oracle yang dapat membedakan yang benar vs yang salah program perilaku dalam kasus umum. Deteksi ras adalah undecidable masalah.
Di sisi lain, data ras memiliki definisi yang tepat yang tidak selalu berhubungan dengan kebenaran, dan oleh karena itu seseorang dapat mendeteksi mereka. Ada banyak rasa dari data ras detektor (statis/dinamis data deteksi ras, lockset data berbasis deteksi ras, terjadi sebelumnya berdasarkan data deteksi ras, hybrid data deteksi ras). Keadaan seni data dinamis ras detektor Sistem yang bekerja sangat baik dalam praktek.
Penanganan data ras secara umum memerlukan beberapa pemrograman disiplin untuk menginduksi terjadi sebelumnya tepi antara akses ke data bersama (baik selama pengembangan, atau setelah mereka terdeteksi dengan menggunakan alat-alat yang disebutkan di atas). hal ini dapat dilakukan melalui kunci, kondisi variabel, semaphore, dll. Namun, dapat juga menggunakan paradigma pemrograman yang berbeda seperti pesan lewat (bukan shared memory) yang menghindari data yang balapan dengan konstruksi.
Semacam-dari-kanonik definisi "ketika dua benang akses lokasi yang sama di memori pada saat yang sama, dan setidaknya salah satu dari yang mengakses adalah menulis." Dalam situasi "pembaca" benang mungkin mendapatkan nilai lama atau baru nilai, tergantung pada mana benang "menang lomba." Ini tidak selalu bug—pada kenyataannya, beberapa benar-benar berbulu tingkat rendah algoritma melakukan ini dengan sengaja—tetapi umumnya harus dihindari. @Steve Gury memberikan's sebuah contoh yang baik dari saat ini mungkin akan menjadi masalah.
Kondisi balapan adalah jenis bug, itu hanya terjadi dengan beberapa kondisi temporal.
Contoh: Bayangkan anda memiliki dua benang, A dan B.
Di Thread:
if( object.a != 0 )
object.avg = total / object.a
Di Thread B:
object.a = 0
Jika thread Yang mendahului hanya setelah memeriksa benda tersebut.a tidak nol, B akan melakukan a = 0
, dan ketika thread akan mendapatkan prosesor, ia akan melakukan "membagi dengan nol".
Bug ini hanya terjadi ketika benang Yang mendahului hanya setelah pernyataan if, it's sangat jarang, tetapi bisa terjadi.
Kondisi balapan ini tidak hanya terkait dengan perangkat lunak tetapi juga terkait dengan perangkat keras. Sebenarnya istilah ini awalnya diciptakan oleh industri hardware.
Menurut wikipedia:
istilah ini berasal dari ide dari dua sinyal balap satu sama lain untuk pengaruh output pertama.
kondisi Balapan di sirkuit logika:
Industri perangkat lunak mengambil istilah ini tanpa modifikasi, yang membuatnya sedikit sulit untuk memahami.
Anda perlu melakukan beberapa penggantian untuk peta ke dunia perangkat lunak:
Jadi kondisi persaingan di industri perangkat lunak berarti "dua benang"/"dua proses" balap satu sama lain untuk "pengaruh bersama beberapa negara", dan hasil akhir dari berbagi negara akan tergantung pada beberapa halus perbedaan waktu, yang bisa disebabkan oleh beberapa thread tertentu/proses launching order, benang/proses penjadwalan, dll.
Perlombaan kondisi yang terjadi pada multi-threaded aplikasi atau multi-proses sistem. Kondisi balapan, paling dasar, adalah sesuatu yang membuat asumsi bahwa dua hal yang tidak di thread yang sama atau proses yang akan terjadi dalam urutan tertentu, tanpa mengambil langkah-langkah untuk memastikan bahwa mereka lakukan. Hal ini terjadi biasanya ketika dua benang yang lewat pesan oleh pengaturan dan memeriksa variabel anggota kelas kedua dapat mengakses. Ada's hampir selalu perlombaan kondisi ketika salah satu thread panggilan tidur untuk memberikan thread lain waktu untuk menyelesaikan tugas (kecuali yang tidur dalam satu lingkaran, dengan memeriksa beberapa mekanisme).
Alat-alat untuk mencegah race conditions tergantung pada bahasa dan OS, tapi beberapa comon yang mutexes, bagian penting, dan sinyal. Mutexes yang baik ketika anda ingin pastikan anda're-satunya orang yang melakukan sesuatu. Sinyal yang baik ketika anda ingin memastikan bahwa orang lain telah selesai melakukan sesuatu. Meminimalkan sumber daya bersama juga dapat membantu mencegah perilaku tak terduga
Mendeteksi kondisi ras dapat menjadi sulit, tetapi ada beberapa tanda-tanda. Kode yang sangat bergantung pada tidur lebih rentan terhadap kondisi balapan, jadi periksa dulu untuk panggilan untuk tidur di tempat yang terkena kode. Menambahkan terlalu lama tidur juga dapat digunakan untuk debugging untuk mencoba dan memaksa urutan tertentu dari peristiwa-peristiwa. Hal ini dapat berguna untuk mereproduksi perilaku, melihat jika anda dapat membuatnya menghilang dengan mengubah waktu dari hal-hal, dan untuk pengujian solusi dimasukkan ke dalam tempat. Tidur harus dihapus setelah debugging.
Tanda tangan tanda bahwa seseorang memiliki kondisi balapan meskipun, adalah jika ada's sebuah masalah yang hanya terjadi sebentar-sebentar pada beberapa mesin. Umum bug yang akan crash dan deadlock. Dengan login, anda harus dapat menemukan daerah yang terkena dan bekerja kembali dari sana.
Race condition adalah situasi di concurrent programming di mana dua benang bersamaan atau proses yang bersaing untuk sumber daya dan menghasilkan keadaan akhir tergantung pada siapa yang mendapat sumber pertama.
Microsoft sebenarnya telah menerbitkan benar-benar rinci artikel dalam hal ini ras dan kondisi deadlock. Yang paling diringkas abstrak dari itu akan menjadi judul ayat:
perlombaan kondisi yang terjadi ketika dua benang akses bersama pada variabel waktu yang sama. Thread pertama berbunyi variabel, dan kedua benang membaca nilai yang sama dari variabel. Kemudian thread pertama dan kedua benang melakukan operasi mereka pada nilai, dan mereka ras untuk melihat thread yang dapat menulis nilai terakhir bersama variabel. nilai dari benang yang menulis nilai terakhir yang diawetkan, karena benang menulis lebih dari nilai yang sebelumnya benang menulis.
Apa adalah kondisi balapan?
Situasi ketika proses ini sangat tergantung pada urutan atau waktu acara lainnya.
Misalnya, Processor dan processor B kebutuhan identik sumber daya untuk eksekusi mereka.
Bagaimana anda mendeteksi mereka?
Ada alat untuk mendeteksi kondisi balapan secara otomatis:
Bagaimana anda menangani mereka?
Perlombaan kondisi dapat ditangani oleh Mutex atau Semaphore. Mereka bertindak sebagai kunci yang memungkinkan sebuah proses untuk memperoleh sumber daya yang didasarkan pada persyaratan-persyaratan tertentu untuk mencegah race condition.
Bagaimana anda mencegah mereka dari terjadi?
Ada berbagai cara untuk mencegah race condition, seperti Bagian Penting Penghindaran.
Berikut ini adalah klasik Saldo Rekening Bank contoh yang akan membantu para pemula untuk memahami Benang di Jawa w dengan mudah.r.t. perlombaan kondisi:
public class BankAccount {
/**
* @param args
*/
int accountNumber;
double accountBalance;
public synchronized boolean Deposit(double amount){
double newAccountBalance=0;
if(amount<=0){
return false;
}
else {
newAccountBalance = accountBalance+amount;
accountBalance=newAccountBalance;
return true;
}
}
public synchronized boolean Withdraw(double amount){
double newAccountBalance=0;
if(amount>accountBalance){
return false;
}
else{
newAccountBalance = accountBalance-amount;
accountBalance=newAccountBalance;
return true;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
BankAccount b = new BankAccount();
b.accountBalance=2000;
System.out.println(b.Withdraw(3000));
}
Race condition adalah situasi yang tidak diinginkan yang terjadi ketika sebuah perangkat atau sistem yang mencoba untuk melakukan dua atau lebih operasi pada saat yang sama, tetapi karena sifat dari perangkat atau sistem operasi yang harus dilakukan dalam urutan yang tepat agar dapat dilakukan dengan benar.
Dalam memori komputer atau penyimpanan, kondisi persaingan dapat terjadi jika perintah untuk membaca dan menulis data dalam jumlah besar yang diterima pada saat yang hampir bersamaan, dan mesin usaha untuk menimpa beberapa atau semua data lama sementara itu data lama masih sedang anda baca. Hasilnya mungkin satu atau lebih dari berikut ini: crash komputer, aplikasi "operasi ilegal," pemberitahuan dan mematikan program, kesalahan membaca data lama, atau kesalahan penulisan data baru.
Anda dapat mencegah race condition, jika anda menggunakan "Atom" kelas-kelas. Alasannya adalah hanya benang don't operasi terpisah get dan set, contoh di bawah ini:
AtomicInteger ai = new AtomicInteger(2);
ai.getAndAdd(5);
Sebagai hasilnya, anda akan memiliki 7 di link "ai". Meskipun anda melakukan dua tindakan, tetapi kedua operasi mengkonfirmasi thread yang sama dan tidak ada thread lain yang akan mengganggu untuk ini, itu berarti tidak ada kondisi ras!
Race condition adalah situasi yang tidak diinginkan yang terjadi ketika dua atau lebih proses dapat mengakses dan mengubah data bersama pada waktu yang sama.Hal itu terjadi karena ada yang bertentangan mengakses ke sumber daya . Penting bagian masalah dapat menyebabkan kondisi balapan. Untuk mengatasi kondisi kritis antara proses kami telah mengambil hanya satu proses pada satu waktu yang mengeksekusi critical section.
Mencoba ini contoh dasar untuk pemahaman yang lebih baik dari kondisi balapan:
public class ThreadRaceCondition {
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Account myAccount = new Account(22222222);
// Expected deposit: 250
for (int i = 0; i < 50; i++) {
Transaction t = new Transaction(myAccount,
Transaction.TransactionType.DEPOSIT, 5.00);
t.start();
}
// Expected withdrawal: 50
for (int i = 0; i < 50; i++) {
Transaction t = new Transaction(myAccount,
Transaction.TransactionType.WITHDRAW, 1.00);
t.start();
}
// Temporary sleep to ensure all threads are completed. Don't use in
// realworld :-)
Thread.sleep(1000);
// Expected account balance is 200
System.out.println("Final Account Balance: "
+ myAccount.getAccountBalance());
}
}
class Transaction extends Thread {
public static enum TransactionType {
DEPOSIT(1), WITHDRAW(2);
private int value;
private TransactionType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
};
private TransactionType transactionType;
private Account account;
private double amount;
/*
* If transactionType == 1, deposit else if transactionType == 2 withdraw
*/
public Transaction(Account account, TransactionType transactionType,
double amount) {
this.transactionType = transactionType;
this.account = account;
this.amount = amount;
}
public void run() {
switch (this.transactionType) {
case DEPOSIT:
deposit();
printBalance();
break;
case WITHDRAW:
withdraw();
printBalance();
break;
default:
System.out.println("NOT A VALID TRANSACTION");
}
;
}
public void deposit() {
this.account.deposit(this.amount);
}
public void withdraw() {
this.account.withdraw(amount);
}
public void printBalance() {
System.out.println(Thread.currentThread().getName()
+ " : TransactionType: " + this.transactionType + ", Amount: "
+ this.amount);
System.out.println("Account Balance: "
+ this.account.getAccountBalance());
}
}
class Account {
private int accountNumber;
private double accountBalance;
public int getAccountNumber() {
return accountNumber;
}
public double getAccountBalance() {
return accountBalance;
}
public Account(int accountNumber) {
this.accountNumber = accountNumber;
}
// If this method is not synchronized, you will see race condition on
// Remove syncronized keyword to see race condition
public synchronized boolean deposit(double amount) {
if (amount < 0) {
return false;
} else {
accountBalance = accountBalance + amount;
return true;
}
}
// If this method is not synchronized, you will see race condition on
// Remove syncronized keyword to see race condition
public synchronized boolean withdraw(double amount) {
if (amount > accountBalance) {
return false;
} else {
accountBalance = accountBalance - amount;
return true;
}
}
}
Anda don't selalu ingin buang kondisi balapan. Jika anda memiliki bendera yang dapat dibaca dan ditulis oleh beberapa thread, dan ini bendera diatur ke 'selesai' oleh satu benang agar benang lain berhenti memproses ketika bendera diatur ke 'selesai', anda don't ingin bahwa "kondisi balapan" untuk dihilangkan. Pada kenyataannya, ini dapat disebut sebagai jinak kondisi balapan.
Namun, dengan menggunakan alat untuk deteksi kondisi balapan, maka akan terlihat sebagai berbahaya kondisi balapan.
Rincian lebih lanjut tentang kondisi balapan di sini, http://msdn.microsoft.com/en-us/magazine/cc546569.aspx.
Pertimbangkan operasi yang memiliki tampilan yang dihitung segera setelah menghitung akan bertambah. ie., sesegera CounterThread penambahan nilai DisplayThread kebutuhan untuk menampilkan baru-baru ini diperbarui nilai.
int i = 0;
Output
CounterThread -> i = 1
DisplayThread -> i = 1
CounterThread -> i = 2
CounterThread -> i = 3
CounterThread -> i = 4
DisplayThread -> i = 4
Di sini CounterThread mendapat kunci yang sering dan update nilai sebelum DisplayThread menampilkan itu. Di sini ada kondisi Balapan. Kondisi balapan dapat diselesaikan dengan menggunakan Synchronzation