Semaphore does not invoke release()

Tags: , , ,



I have implemented a thread in an Android app that is invoked every minute, the invocation of the process occur through an Alarm Manager.

@Override
public void onReceive(Context context, Intent intent) {
    try {
        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wakeLock;
        if (powerManager != null) {
            wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Send-data");
            wakeLock.acquire(10 * 60 * 1000L);
            new Thread(new SendPolicyData(context)).start();
            wakeLock.release();
        }
    } catch (Exception e) {
        wil.WriteFile("1)AlarmSendData - Exception: " + e.toString());
    }
}

The code contained in the thread extract a set of data from a database that must be sent through posts to a server, the access to resources is controlled via a semaphore.

@SuppressWarnings("ResultOfMethodCallIgnored")
public class SendPolicyData implements Runnable {
    private static final WriteInLogFile wil = new WriteInLogFile();
    private final Context ctx;

public SendPolicyData(Context ctx) {
    this.ctx = ctx;
}

public void run() {
    try {
        SemaphoreDTS.getInstance().goIn();

        Authentication singleCall = new Authentication();
        Utilities utilities = new Utilities(ctx);
        DbGest dbGest = DbGest.getInstance(ctx);

        if (utilities.checkConnection()) {
            int lastProcessedID = -1;
            int attempts = 0;

            Cursor cursor = dbGest.freeQuery("SELECT id, label, value, priority FROM " + TABLE_DATATOSEND + " ORDER BY priority,dateIns");
            if (cursor != null) {
                cursor.moveToFirst();
                if (cursor.getCount() > 0) {
                    do {
                        int toProcessID = cursor.getInt(cursor.getColumnIndex("id"));
                        String value = cursor.getString(cursor.getColumnIndex("value"));
                        String labelString = cursor.getString(cursor.getColumnIndex("label"));

                        if (lastProcessedID == toProcessID) {
                            if (attempts <= 5) {
                                attempts++;
                                Thread.sleep(3000);
                            } else {
                                attempts = 0;
                                dbGest.changeDTSRecordPriority(toProcessID);
                            }
                        }

                        switch (labelString) {
                            case "photo":
                               //DO STUFF
                             break;
                        lastProcessedID = toProcessID;
                    } while (cursor.moveToNext());
                }
                cursor.close();
            }
        }
    } catch (Exception e) {
        SemaphoreDTS.getInstance().goOut();
        wil.WriteFile("7)SendPolicyData - Exception: " + e.toString());
    } finally {
        SemaphoreDTS.getInstance().goOut();
    }
    SemaphoreDTS.getInstance().goOut();
}

}

This is the source code of the semaphore that I use to manage the access to the resources.

public class SemaphoreDTS {
    private static SemaphoreDTS instance;
    private final Semaphore semaphore;
    private final WriteInLogFile wil = new WriteInLogFile();

private SemaphoreDTS() {
    this.semaphore = new Semaphore(1, true);
}

public static SemaphoreDTS getInstance() {
    if (instance == null) {
        instance = new SemaphoreDTS();
    }
    return instance;
}

public synchronized void goIn() {
    try {
        semaphore.acquire();
    } catch (Exception e) {
        wil.WriteFile("1)SemaphoreDTS - Exception: " + e.toString());
    }
}

public synchronized void goOut() {
    try {
        semaphore.release();
    } catch (Exception e) {
        wil.WriteFile("2)SemaphoreDTS - Exception: " + e.toString());
    }
}
}

During the tests that I did, it often happens that the semaphore remains blocked, for some reason the necessary release is not invoked in order to be able to perform new acquire.

I think I have written the code correctly and I don’t understand where I am wrong.

Answer

In this code’s block:

catch (Exception e) {
        SemaphoreDTS.getInstance().goOut();
        wil.WriteFile("7)SendPolicyData - Exception: " + e.toString());
    } finally {
        SemaphoreDTS.getInstance().goOut();
    }
    SemaphoreDTS.getInstance().goOut();

You always have two calls .goOut(), because finally block always will invoke. When you call .release() (in your method .goOut()) semaphore gets availible permit, i.e instead 1 permit your semaphore gets 2 permits. I think problem starts here. Try to delete calls `.goOut() method everywhere but not in finally()



Source: stackoverflow