Что не так с моим приложением семафора? - PullRequest
3 голосов
/ 01 ноября 2019

Целью программы является симуляция того, что несколько пользователей добавляют число в буфер от 0 до n. Затем выведите сумму чисел в буфере. Когда я запускаю программу, кажется, что потоки никогда не заканчиваются. Тем не менее, поток закончится, когда я запущу программу в режиме отладки Idea и шаг за шагом. Кроме того, я точно не знаю, где мне нужно использовать мой метод семафоров P() и V() для взаимного исключения.

Версия: JDK 8. Я не могу использовать семафор в библиотеке.

Main.java

Buffer b = new Buffer(bufferSize);                      
ArrayList<user> us = new ArrayList<>();
for(int i = 0; i < num_users; i++) us.add(new user(i, elements, b));
ArrayList<Thread> th = new ArrayList<>();
for(int i = 0; i < num_users; i++)
{
    th.add(new Thread(us.get(i)));
    th.get(i).start();
}

user.java

public class user implements Runnable
{                               
    private int id;
    private int num_elements;
    private semaphore mutex = new semaphore(1 );
    public static Buffer buf;

    public user(int i, int el, Buffer b)                        
        {id = i; num_elements = el; buf = b;}

    public void add_elements()
    {//Add element to buffer, element value iterates from 0, 1, 2 .... num_elements
        mutex.P();
        int n = 0;
        while (num_elements > 0)
        {                       
            buf.add(new Integer(n));                            
            n++;
            num_elements--;
        }
        mutex.V();
    }

    public void run()
    {
        add_elements();
    }
}

Buffer.java

public class Buffer
{                                       
    private LinkedList<Object> buf_list;        
    private int elements;                       //Number of elements currently on the queue
    private int buf_size;                       //Maximum number of elements allowed on queue
    private semaphore mutex = new semaphore(1);

    public Buffer(int n)                        //Queue creation, with n indicating the maximum capacity
    {
        buf_list = new LinkedList<Object>();
        elements = 0;
        buf_size = n;
    }

    public void add(Integer n)
    {       
        mutex.P();
        buf_list.add(n);
        elements++;
        mutex.V();
    }

    public void finalSummation()                
    {                       
        if (elements == buf_size)
        {
            mutex.P();
            int sum = 0;
            for (Object n : buf_list)
                sum += ((Integer)n).intValue();
            mutex.V();
            System.out.println("Count total: " + sum); 
        }
    }
}

семафор.java

public class semaphore
{
    private int count = 0;

    public semaphore(int init_count)
    {
        count = init_count;
    }

    public synchronized void P()
    {
        count -= 1;
        while (count < 0)
        {
            try { 
                wait();
            } catch (InterruptedException e)  {
                System.out.println("Error");
                System.exit(-1);
            }
        }
    }

    public synchronized void V()
    {
        count += 1;
        notifyAll();
    }
}   

Iожидается, что он напечатает сумму номеров буферов, но поток может не завершиться.

Ответы [ 2 ]

1 голос
/ 01 ноября 2019

Есть несколько вещей, которые выделяются здесь как проблемы.

1) ваш код никогда не вызывает метод finalSummation. Таким образом, «печать» результата никогда не произойдет.

2) Буфер и каждый пользователь создают свои собственные семафоры. Если вы пытаетесь разрешить нескольким потокам обновлять буфер без коллизий, вам нужно использовать один и тот же семафор. Удалите семафор и его использование из пользовательского класса. Просто позвольте экземпляру Buffer контролировать только одно обновление за раз со своим семафором.

3) Вам не нужно проверять семафор в методе finalSummation. Предположительно, все темы сделаны на этом этапе. И чтобы обеспечить это ...

4) Поместите такой код в конец main

for(int i = 0; i < num_users; i++) {
    th.get(i).join();
}
b.finalSummation();

5) Семафор должен управлять несколькими разрешениями. Ваш семафор управляет количеством ожидающих экземпляров - это в значительной степени не имеет значения для семафора. Измените ваши P () и V () на acqu () и release () в соответствии с шаблоном.

public static class semaphore {
    private int permits = 0;

    public semaphore(int permits) {
        this.permits = permits;
    }

    public synchronized void acquire() {
        while (permits < 1) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("Error");
                System.exit(-1);
            }
        }
        permits--;
    }

    public void release() {
        synchronized (this) {
            permits += 1;
            notifyAll();
        }
    }
}
0 голосов
/ 02 ноября 2019

Я собрал его, используя ответ выше, если это поможет. Пожалуйста, выберите ответ выше как правильный ответ.

import java.util.ArrayList;
import java.util.LinkedList;

public class Main {

    // assumed values
    private static final int bufferSize = 5;
    private static final int num_users = 10;
    private static final int elements = 5;

    public static void main(String[] args) {

        Buffer b = new Buffer(bufferSize);                      
        ArrayList<User> us = new ArrayList<>();

        for(int i = 0; i < num_users; i++) us.add(new User(i, elements, b));
        ArrayList<Thread> th = new ArrayList<>();
        for(int i = 0; i < num_users; i++)
        {
            th.add(new Thread(us.get(i)));
            th.get(i).start();
        }       
        for(int i = 0; i < num_users; i++) {
            try {
                th.get(i).join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        b.finalSummation();
        System.out.println("Exiting");

    }

}

class User implements Runnable
{                               
    private int id;
    private int num_elements;
    public static Buffer buf;

    public User(int i, int el, Buffer b)                        
        {id = i; num_elements = el; buf = b;}

    public void add_elements()
    {//Add element to buffer, element value iterates from 0, 1, 2 .... num_elements
        int n = 0;
        while (num_elements > 0)
        {                       
            buf.add(new Integer(n));                            
            n++;
            num_elements--;
        }
    }

    public void run()
    {
        add_elements();
    }
}

class Buffer
{                                       
    private LinkedList<Object> buf_list;        
    private int elements;                       //Number of elements currently on the queue
    private int buf_size;                       //Maximum number of elements allowed on queue
    private Semaphore mutex ;

    public Buffer(int n)                        //Queue creation, with n indicating the maximum capacity
    {
        buf_list = new LinkedList<Object>();
        elements = 0;
        buf_size = n;
        mutex = new Semaphore(buf_size);
    }

    public synchronized void  add(Integer n)
    {       
        mutex.acquire();
        buf_list.add(n);
        elements++;
        mutex.release();
    }

    public  void finalSummation()                
    {                       
        int sum = 0;
        System.out.println(buf_list);
        for (Object n : buf_list)
            sum += ((Integer)n).intValue();
        System.out.println("Count total: " + sum); 
    }
}

class Semaphore {
    private int permits = 0;

    public Semaphore(int permits) {
        this.permits = permits;
    }

    public synchronized void acquire() {
        while (permits < 1) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("Error");
                System.exit(-1);
            }
        }
        permits--;
    }

    public void release() {
        synchronized (this) {
            permits += 1;
            notifyAll();
        }
    }
}
...