(x | y) - y neden sadece x, hatta x olamaz? 0`


47

Bir çekirdek kodlarını okuyordu ve tek bir yerde içimde bir ifade gördüm ifaçıklamada gibi

if (value == (SPINLOCK_SHARED | 1) - 1) {
         ............
}

nerede SPINLOCK_SHARED = 0x80000000önceden tanımlanmış bir sabittir.

Acaba neden (SPINLOCK_SHARED | 1) - 1dönüştürme ihtiyacımız var ? ifadenin sonucu 80000000 olur - 0x80000000 ile aynıdır, değil mi? yine de neden ORing 1 ve 1 Çıkarma önemlidir?

Bir şey almak için özlediğim gibi hissediyorum.


3
#define SPINLOCK_SHARED 0x80000000
RaGa__M

1
Bunun bir nedeni olmadığından şüpheleniyorum. Muhtemelen bir kopyala yapıştır özelliği. Bunu tam olarak bulduğunuz yeri (hangi sürümün çekirdeği, hangi dosya vb.) Ekleyebilir misiniz?
Sander De Dycker


2
Aynı kaynak kodu dosyası da içerir if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED|0, 1)).
Eric Postpischil

2
O zaman yazarın neden değiştirildiğini sormamız gerektiğini düşünüyorum.
funnydman

Yanıtlar:


1

Sadece netlik için bu şekilde yapıldı, hepsi bu. Çünkü atomic_fetchadd_int () (örneğin sys / spinlock2.h) toplama / çıkarma için PRIOR değerini döndürür ve bu değerin _spin_lock_contested () 'e iletilir

C derleyicisinin tüm sabit ifadeleri tamamen önceden hesapladığını unutmayın. Aslında, derleyici, yordamlar bu bağımsız değişkenlerde sabitler iletildiğinde geçirilen yordam bağımsız değişkenlerini kullanan koşullara dayalı olarak satır içi kodu en iyi duruma getirebilir. Bu nedenle sys / lock.h dosyasında lockmgr () satır içi bir vaka deyimi vardır .... çünkü tüm vaka deyimi optimize edilecek ve uygun işleve doğrudan çağrıya dönüşecektir.

Ayrıca, tüm bu kilitleme fonksiyonlarında, atomik oplerin ek yükü diğer tüm hesaplamaları iki veya üç büyüklükte cüce eder.

-Mat


Bu cevap yazardan !!!
RaGa__M

31

Kod, başka bir kişi kilidi almaya çalışırken _spin_lock_contestedçağrılır _spin_lock_quick:

count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
    _spin_lock_contested(spin, ident, count);
}

Yarışma yoksa, count(önceki değer) olmalı 0, ama değil. Bu countdeğer parametre olarak parametresi _spin_lock_contestedolarak geçirilir value. Bu valuedaha sonra OP'den kontrol edilir if:

/*
 * WARNING! Caller has already incremented the lock.  We must
 *      increment the count value (from the inline's fetch-add)
 *      to match.
 *
 * Handle the degenerate case where the spinlock is flagged SHARED
 * with only our reference.  We can convert it to EXCLUSIVE.
 */
if (value == (SPINLOCK_SHARED | 1) - 1) {
    if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED | 1, 1))
        return;
}

valueÖnceki değerin olduğunu spin->countave ikincisinin zaten 1 arttırıldığını akılda tutarak, spin->countaeşit olmayı bekliyoruz value + 1(bu arada bir şey değişmedikçe).

Bu nedenle, spin->counta == SPINLOCK_SHARED | 1(ön koşulunun atomic_cmpset_int) value + 1 == SPINLOCK_SHARED | 1yeniden yazılabilir olup olmadığını kontrol etmeye karşılık gelip gelmediğini kontrol etmek value == (SPINLOCK_SHARED | 1) - 1(bu arada hiçbir şey değişmediyse).

İken value == (SPINLOCK_SHARED | 1) - 1şekilde tekrar yazılabilir value == SPINLOCK_SHARED, bu karşılaştırmanın niyet netleştirmek için, olduğu gibi kalan (yani. Test değeri ile artırılır önceki değerini karşılaştırmak için).

Veya iow. cevabın açıklık ve kod tutarlılığı için olduğu görülmektedir.


Yanıtınız için teşekkürler, (SPINLOCK_SHARED | 1) - 1bölüm dışındaki her şey anlaşılabilir ve value == SPINLOCK_SHAREDbenim de düşüncelim, çünkü önceki değerin paylaşılan bayrak ayarlı olup olmadığını kontrol ediyoruz. Evetse, kilidi özel hale getirin .........
RaGa__M

1
@ RaGa__M: Çekin amacı (bu arada hiçbir şey değişmemiş gibi aynı değer olmalıdır) ifolup olmadığını kontrol etmektir . Çeki şu şekilde yazarsanız , bu amaç açık değildir ve çekin ne anlama geldiğini anlamak çok daha zor olacaktır. Her ikisini de ve açıkça kontrol altında tutmak kasıtlıdır. value + 1spin->countaSPINLOCK_SHARED | 1ifvalue == SPINLOCK_SHAREDSPINLOCK_SHARED | 1- 1if
Sander De Dycker

Ama aslında karışıklığa neden oluyor.
RaGa__M

Neden olmasın if (value + 1 == (SPINLOCK_SHARED | 1) )?
Pablo H

Şey .... sadece value & SPINLOCK_SHAREDdaha okunabilir olabilir.
RaGa__M

10

Amaç muhtemelen en düşük anlamlı bit göz ardı etmektir:

  • İkili olarak ifade edilen SPINLOCK_SHARED xxx0 ise -> sonuç xxx0
  • SPINLOCK_SHARED = xxx1 -> sonuç da xxx0 ise

belki biraz maske ifadesi kullanmak daha net olurdu?


8
Kodun yaptığı şey budur , fakat soru şudur: Bunu neden en az anlamlı biti ayarlanmamış bir sabit için yapasınız?
Sander De Dycker

4
@SanderDeDycker Linux çekirdeği nedeniyle mi?
Lundin

9
@Lundin Linux çekirdeği anlaşılır kodlama uygulamalarından muaf değildir. Tam tersi.
Qix - MONICA

2
@Qix Eğer öyle diyorsan. Koda bakıp çekirdek kodlama stili belgesini okuyana kadar Linux'un büyük bir hayranıydım. Bugünlerde Linux bilgisayarlara 10 metrelik güvenlik mesafesini koruyorum.
Lundin

2
@Qix Nah Kaynak koduna göre değerlendiriyorum ...
Lundin

4

Etkisi

(SPINLOCK_SHARED | 1) - 1

ile karşılaştırmadan önce sonucun düşük dereceli bitinin temizlenmesini sağlamaktır value. Oldukça anlamsız göründüğünü kabul ediyorum, ancak görünüşe göre düşük dereceli bit, bu kodda belirgin olmayan belirli bir kullanım veya anlama sahip ve sanırım geliştiricilerin bunu yapmak için iyi bir nedeni olduğunu varsaymalıyız. İlginç bir soru olurdu - bu aynı desen ( | 1) -1) baktığınız kod tabanı boyunca kullanılıyor mu?


2

Biraz maske yazmanın karışık bir yolu. Okunabilir versiyon: value == (SPINLOCK_SHARED & ~1u).


5
Evet, ama neden . OP bilinen bir sabitse neden böyle olacağını soruyor SPINLOCK_SHARED. SPINLOCK_SHAREDBir maskede bulunup bulunmadığını test ediyorlarsa , neden olmasın if (value & SPINLOCK_SHARED)?
Qix - MONICA

4
value == (SPINLOCK_SHARED & ~1u)eşdeğer değildir, çünkü value == (SPINLOCK_SHARED | 1) - 1türü SPINLOCK_SHAREDdaha geniş olsa bile çalışır unsigned.
Eric Postpischil

4
Dürüst olmak gerekirse, bunun & ~1udaha net olduğundan emin değilim . & 0xFFFFFFFECevabımı önermeyi düşündüm ama bunun da çok net olmadığını fark ettim. Ancak önerilerinizin kısalık avantajı var. :-)
Bob Jarvis - Monica'yı

6
@Lundin: Bunun olacağını bilmiyoruz 0x80000000. OP bunun ile tanımlandığını #define SPINLOCK_SHARED 0x80000000, ancak bunun içinde olabileceğini #if…#endifve başka durumlarda farklı bir tanım kullanıldığını veya bu kodun yazarı, tanım düzenlenmiş olsa veya kod, farklı tanımlayın. Ne olursa olsun, iki kod parçası kendi başlarına eşdeğer değildir.
Eric Postpischil

2
@ BobJarvis-ReinstateMonica Her gün bitsel operatörlerle çalışan insanlar için çok daha net. Normal aritmetik ile bitsel olarak karıştırmak kafa karıştırıcıdır.
Lundin

0

Bunun gibi çoğu, birkaç ek vakayı ele almak için yapılır. Örneğin, bu durumda, SPINLOCK_SHARED1 olamaz diyoruz :

int SPINLOCK_SHARED = 0x01

int res = (SPINLOCK_SHARED | 1) - 1 // 0

2
Bu mantıklı olurdu, ancak aslında sorudan net olmasa da, SPINLOCK_SHAREDtanımlanmış bir sabit gibi ve test edilen değişken olduğu gibi geliyor value. Bu durumda buğulanma kalır.
Roberto Caboni

Cevabınız için teşekkürler, Ama orijinal durumda SPINLOCK_SHARED 0x01 değil, | 1) - 1tho parçası tuttunuz, SPINLOCK_SHARED tutma 0x80000000sırasında etkisi ne olurdu | 1) - 1?
RaGa__M

Düşünebilmemin tek nedeni SPINLOCK_SHARED, gelecekte değişime karşı korunmak istedikleri . Ama hiç de net değil. Çekirdek geliştiricilere yazarım ve bir açıklama açıklaması yapılmasını ya da ifadenin kendi kendini belgelemesi için yeniden düzenlenmesini isterdim.
Qix - MONICA
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.