2012-06-28 71 views
1

我有一些線程來寫資源和一些讀取它。但pthread_rwlock導致大量的上下文切換。所以我想象一種避免它的方法。但我不確定它是否安全。原子變量可以代替pthread_rwlock嗎?它可以鎖無

這是代碼:

sig_atomic_t slot = 0; 

struct resource { 
    sig_atomic_t in_use; /*Counter,if in_use, not zero*/ 
    ..... 
} xxx[2]; 

int read_thread() 
{ 
    i = slot; /*avoid slot changes in process */ 
    xxx[i].in_use++; 
    read(xxx[i]); 
    xxx[i].in_use--; 
} 

int write_thread() 
{ 
    mutex_lock; /*mutex between write threads */ 

    if (slot == 0) { 
    while(xxx[1].in_use != 0); /*wait last read thread in slot 1*/ 
    clear(xxx[1]); 
    write(xxx[1]); 
    slot = 1; 
    } else if (slot == 1) { 
    while(xxx[0].in_use != 0); 
    clear(xxx[0]); 
    write(xxx[0]); 
    slot = 0; 
    } 

    mutex_unlock; 
} 

威爾的作品?成本是2倍存儲和3個原子變量。 非常感謝!

+0

什麼阻止在閱讀時進行閱讀?閱讀從不等待。 – stark

+0

單線程內存屏障環形緩衝區如何? – 2012-07-03 08:48:36

回答

0

您的策略是讓作家寫入不同於讀者閱讀的插槽。寫入完成後,您正在切換讀取插槽編號。但是,你會有一場比賽。

slot reader    writer1   writer2 
---- ------    -------   ------- 
0       mutex_lock 
     i = 0 
          ... slot=1 
1       mutex_unlock  mutex_lock 
               ... clear(xxx[0]) 
     xxx[0].in_use++ 
     read(xxx[0])       write(xxx[0]) 

總的來說,這種策略可能導致作家的飢餓(這是一個作家可能永遠旋轉)。

但是,如果您願意容忍這種情況,讓xxx[]成爲指向resource的2個指針的數組會更安全。讓讀者始終閱讀xxx[0],並讓作家在xxx[1]上競爭更新。當作家完成更新xxx[1]時,它在xxx[0]xxx[1]上使用CAS。

struct resource { 
    sig_atomic_t in_use; /*Counter,if in_use, not zero*/ 
    sig_atomic_t writer; 
    ..... 
} *xxx[2]; 

void read_thread() 
{ 
    resource *p = xxx[0]; 
    p->in_use++; 
    while (p->writer) { 
     p->in_use--; 
     p = xxx[0]; 
     p->in_use++; 
    } 
    read(*p); 
    p->in_use--; 
} 

void write_thread() 
{ 
    resource *p; 
    mutex_lock; /*mutex between write threads */ 
    xxx[1]->writer = 1; 

    while(xxx[1]->in_use != 0); /*wait last read thread in slot 1*/ 
    clear(xxx[1]); 
    write(xxx[1]); 
    xxx[1] = CAS(&xxx[0], p = xxx[0], xxx[1]); 
    assert(p == xxx[1]); 

    xxx[0]->writer = 0; 
    mutex_unlock; 
} 

如果你想避免寫入器資源匱乏,但你要自旋鎖的性能,你是在尋找實現使用自旋鎖,而不是互斥鎖自己的讀/寫鎖。谷歌搜索「讀寫自旋鎖實現」指向this page,我發現這是一個有趣的閱讀。

+0

這真是太棒了 – HardySimpson

+0

您的建議解決方案與您在OP代碼中標識的方法類似 - 閱讀器可以加載指針值「xxx [0]」,然後寫入器交換「xxx [1]」和「xxx [ 0]',那麼另一個寫入者進來並開始修改新的'xxx [1]'(舊的'xxx [0]'),然後讀取器將指針解除引用並執行增量操作。 – caf

+0

@caf:謝謝你!我修改了算法。問候 – jxh

1

你的算法不是無鎖的;作家使用自旋鎖。

真的有必要做雙緩衝和自旋鎖嗎?您可以改爲使用(slot^1)作爲寫入插槽,而使用slot作爲讀取插槽?寫完之後,作者會自動更改slot的值,從而「發佈」其寫作。你可以用這種方式連續多次讀取同一個槽,但如果這不是你想要的語義,那麼你應該使用一個隊列。

順便說一句,sig_atomic_t不提供多線程所需的原子類型。至少,您應該聲明slotvolatile sig_atomic_t,並在讀寫時使用內存屏障。

+0

謝謝你的sig_atomic_t,是的,它不是原子的。 – HardySimpson