简体   繁体   中英

Thread-Safe way to access EclipsePreferences (Project)

I am currently developing an Eclipse-RCP application that stores per-project preferences using the EclipsePreference mechanism through ProjectScope . At first this seemed to work very well, but we have run into trouble when (read-) accessing these preferences in multithreaded scenarios while at the same time changes are being made to the workspace. What appears to be praticularly problematic is accessing such a preference node ( ProjectScope.getNode() ) while the project is being deleted by an asynchronous user action (right click on Project -> Delete Project). In such cases we get a pretty mix of

  • org.osgi.service.prefs.BackingStoreException
  • java.io.FileNotFoundException
  • org.eclipse.core.runtime.CoreException

Essentially they all complain that the underlying file is no longer there.

Initial attempts to fix this using checks like IProject.exists() or isAccessible() and even going so far as checking the presence of the actual .prefs file were as futile as expected: They only make the exceptions less likely but do not really prevent them.

So my question is: How are you supposed to safely access things like ProjectScope.getNode() ? Do you need to go so far to put every read into a WorkspaceJob or is there some other, clever way to prevent the above problems like putting the read access in Display.asyncExec() ?

Although I tried, I did not really find answers to the above question in the Eclipse documentation.

Usually scheduling rules are used to concurrently access resources in the workspace.

I've never worked with ProjectScope ed preferences but if they are stored within a project or its metadata, then a scheduling rule should help to coordinate access. If you are running the preferences access code in a Job, then setting an appropriate scheduling rule should do:

For example:

IProject project = getProjectForPreferences( projectPreferences );
ISchedulingRule rule = project.getWorkspace().getRuleFactory().modifyRule( project );
Job job = new Job( "Access Project Preferences" ) {
  @Override
  protected IStatus run( IProgressMonitor monitor ) {
    if( project.exists() ) {
      // read or write project preferences
    }
    return Status.OK_STATUS;
  }
};
job.setRule( rule );
job.schedule();

The code acquires a rule to modify the project and the Job is guaranteed to run only when no other job with a conflichting rule runs.

If your code isn't running within a job, you can also manually acquire a lock with IJobManager.beginRule() and endRule() .

For example:

ISchedulingRule rule = ...;
try {
  jobManager.beginRule( rule, monitor );
  if( project.exists() ) {
    // read or write project preferences
  }
} finally {
  jobManager.endRule( rule );
}

As awkward as it looks, the call to beginRule must be within the try block, see the JavaDoc for more details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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