简体   繁体   English

如何在读取时阻止从线程对数组的写入访问

[英]How to block write access to the array from Thread while reading

I have two threads running parallel, and to get information about their internal results, I have created int array of length 8. With respect to their id, they can update relative area on the statu array. 我有两个并行运行的线程,并且为了获取有关其内部结果的信息,我创建了一个长度为8的int数组。关于其ID,它们可以更新statu数组上的相对面积。 They are not let to write others area. 他们不被允许去写别人的领域。 Moreover, to correctly get and display statu array, I try to write getStatu method. 此外,为了正确获取和显示statu数组,我尝试编写getStatu方法。 While getting the result, I want to block others to write to the statu array; 在获得结果的同时,我想阻止其他人写入statu数组。 unfortunately, I donot get how to block other to write the statu array while I am getting and displaying result in getStatu method. 不幸的是,当我在getStatu方法中获取并显示结果时,我没有得到如何阻止他人编写statu数组的信息。 How? 怎么样?

Note: If there is a part to cause misunderstood, tell me my friend, I will fix 注意:如果有引起误解的部分,请告诉我我的朋友,我会解决

class A{
    Semaphore semaphore;
    int [] statu;  // statu is of length 8

    void update(int idOfThread, int []statu_){
        try {
            semaphore.acquire();
            int idx = idOfThread * 4;

            statu[idx] = statu_[0];
            statu[idx+1] = statu_[1];
            statu[idx+2] = statu_[2];
            statu[idx+3] = statu_[3];
        } catch (...) {

        } finally {
            semaphore.release();
        }
    }

    int[] getStatu(){
        // Block write access of threads
        //    display statu array
        //    return statu array as return value
        // release block, so threads can write to the array

    }
}

Apart from using another lock/snc mechanism than Semaphore, just a proposal to improve this a little. 除了使用Semaphore之外的其他锁/ snc机制之外,还只是提出了一些改进建议。

Putting both status[4] arrays into a single array[8] is not hte best solution. 将两个status [4]数组放入单个array [8]并不是最佳解决方案。 Consider task A writing its quadruplet: it must lock out task B reading the same, but there's no point in locking out task B writing B's quadruplet, and vice versa. 考虑任务A写入其四联体:它必须锁定任务B读取相同的四元组,但是锁定任务B写入B的四联体毫无意义,反之亦然。

Generally speaking, the granularity of what is being locked is one important factor: locking the entire database is nonsense (except for overall processing like backup), however locking individual fields of a record would produce excessive overhead. 一般而言,锁定对象的粒度是一个重要因素:锁定整个数据库是无稽之谈(除了诸如备份之类的整体处理之外),但是锁定记录的各个字段会产生过多的开销。

There are possibly better ways to get to where you want to, but only you know what you are trying to do. 可能会有更好的方法到达想要的地方,但只有您知道自己要做什么。 Going with your own scheme, there are things you are doing wrong. 按照您自己的方案,有些事情做错了。 First thing, currently you are not achieving the granular locking you are planning to. 首先,当前您尚未实现计划的粒度锁定。 For that you must have an array of semaphores. 为此,您必须有一个信号量数组。 So the acquisition will look something like 所以收购看起来像

semaphore[idOfThread].acquire();

Secondly, one thing you've not realised is that controlled access to data among threads is a co-operative activity. 其次,您尚未意识到的一件事情是,线程之间对数据的受控访问是一种合作活动。 You cannot lock on one thread and not care to deal with locking on another and somehow impose the access control. 您不能锁定一个线程,也不关心处理另一个线程,并以某种方式强加了访问控制。

So unless the caller of your getStatu() will use the same set of semaphores when inspecting the array, your best bet is for getStatu() to make a new int[] array, copying segments of each thread after locking with the respective semaphore. 因此,除非您的getStatu()的调用者在检查数组时使用相同的信号量集,否则最好的选择是让getStatu()创建一个新的int []数组,并在用相应的信号量锁定后复制每个线程的段。 So the array returned by getStatu() will be a snapshot at the point of call. 因此,getStatu()返回的数组将是调用点的快照。

Please try the below code it will work for you. 请尝试以下代码,它将为您工作。 call afterStatu() in it. 在其中调用afterStatu()

class A {

    Semaphore semaphore;
    int[] statu; // statu is of length 8

    private boolean stuck;

    public A() {
    }

    void update(int idOfThread, int[] statu_) {

        // if true, control will not go further
        while (stuck);

        try {
            semaphore.acquire();
            int idx = idOfThread * 4;

            statu[idx] = statu_[0];
            statu[idx + 1] = statu_[1];
            statu[idx + 2] = statu_[2];
            statu[idx + 3] = statu_[3];
        } catch (Exception e) {

        } finally {
            semaphore.release();
        }
    }

    int[] getStatu() {
        // Block write access of threads
        stuck = true;
        // display statu array
        for (int eachStatu : statu) {
            System.out.println(eachStatu);
        }

        // return statu array as return value
        return statu;
    }

    public void afterStatu() {
        getStatu();
         // release block, so threads can write to the array
        stuck = false;
    }

}
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
int[] statu;

void update() {
    lock.writeLock().lock();
    try {
        // update statu
    } finally {
        lock.writeLock().unlock();
    }
}

int[] getStatu() {
    lock.readLock().lock();
    try {
        // return statu
    } finally {
        lock.readLock().unlock();
    }
}

Like ac3 said, only you know what you are trying to do. 就像ac3所说,只有您知道自己要做什么。

Here's a solution that might be useful in the case where every thread that calls update() does so frequently , and calls to getStatu() are infrequent. 每个调用update()的线程都如此频繁很少调用getStatu()的情况下,这是一个有用的解决方案 It's complex, but it allows most of the update() calls to happen without any locking at all. 这很复杂,但是它允许大多数update()调用发生而根本没有任何锁定。

static final int NUMBER_OF_WORKER_THREADS = ...;
final AtomicReference<CountDownLatch> pauseRequested = new AtomicReference<CountDownLatch>(null);
final Object lock = new Object();

int[] statu = ...

//called in "worker" thread.
void update() {
    if (pauseRequested.get() != null) {
        pause();
    }
    ... update my slots in statu[] array ...
}

private void pause() {
    notifyMasterThatIAmPaused();
    waitForMasterToLiftPauseRequest();
}

private void notifyMasterThatIAmPaused() {
    pauseRequested.get().countDown();
}

private void waitForMasterToLiftPauseRequest() {
    synchronized(lock) {
        while (pauseRequested.get() != null) {
            lock.wait();
        }
    }
}

//called in "master" thread

int[] getStatu( ) {
    int[] result;
    CountDownLatch cdl = requestWorkersToPause();
    waitForWorkersToPause(cdl);
    result = Arrays.copyOf(statu, statu.length);
    liftPauseRequest();
    return result;
}

private CountDownLatch requestWorkersToPause() {
    cdl = new CountDownLatch(NUMBER_OF_WORKER_THREADS);
    pauseRequested.set(cdl);
    return cdl;
}

private void waitForWorkersToPause(CountDownLatch cdl) {
    cdl.await();
}

private void liftPauseRequest() {
    synchronized(lock) {
        pauseRequested.set(null);
        lock.notifyAll();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM