У меня есть несколько потоков (некоторые из которых порождены Процессом X, другими Процессом Y, и так далее), и каждый поток должен записать в файл MyFile
. Однако, если Thread T1
начинает писать в MyFile
во-первых, тогда, когда Thread T2
начинает писать, это должно ожидать T1
выпускать файл, так, чтобы это могло считать содержание, которое было записано в Thread T1
. Другими словами, каждый поток имел бы a finalizeThread
метод, как так:
private void finalizeThread() {
File f = new File("MyFile.dat");
f.createNewFile(); // atomically creates the file, if it doesn't exist
locked_section {
readContentsFromFile(f); // read contents if some other thread already modified the file
modifyContentsFromFile(f); // modify
writeFile(f); // write, so that new threads can see the content modified by this thread
}
}
Мой вопрос: Как я могу выполнить locked_section
в вышеупомянутом коде? Я изучал FileLock
класс, но это говорит в Javadoc, что "Блокировки файла сохранены от имени всей виртуальной машины Java. Они не подходят для управления доступом к файлу несколькими потоками в той же виртуальной машине"..
Если доступ к файлу осуществляется только из вашей программы, то объект синхронизированной блокировки в порядке. Но если вы хотите защитить файл от изменения другими программами во время работы над ним, вы можете использовать возможности Java-блокировки файлов в java.nio.channels.FileLock
(example). Как сказано в тексте, помните, что на некоторых операционных системах программы все равно могут изменять файлы, если не проверять на наличие существующей файловой блокировки.
Это не слишком сложно сделать вручную, но будет зависеть от размера интерфейса. Случаи, когда я делал это, чтобы разрешить использование нашей библиотеки C++ из чистого кода C, и, таким образом, SWIG не был большой помощью. (Может быть, SWIG можно использовать для этого, но я не гуру SWIG и это казалось нетривиальным)
Все, что мы в итоге сделали:
Итак, такой класс, как этот (C++ заголовок)
class MyClass
{
public:
explicit MyClass( std::string & s );
~MyClass();
int doSomething( int j );
}
Будет сопоставляться с C интерфейсом, таким как этот (C заголовок):
struct HMyClass; // An opaque type that we'll use as a handle
typedef struct HMyClass HMyClass;
HMyClass * myStruct_create( const char * s );
void myStruct_destroy( HMyClass * v );
int myStruct_doSomething( HMyClass * v, int i );
Реализация интерфейса будет выглядеть следующим образом (C++ источник)
#include "MyClass.h"
extern "C"
{
HMyClass * myStruct_create( const char * s )
{
return reinterpret_cast<HMyClass*>( new MyClass( s ) );
}
void myStruct_destroy( HMyClass * v )
{
delete reinterpret_cast<MyClass*>(v);
}
int myStruct_doSomething( HMyClass * v, int i )
{
return reinterpret_cast<MyClass*>(v)->doSomething(i);
}
}
Мы извлекаем наш непрозрачный дескриптор из исходного класса, чтобы избежать необходимости в литье, и (Это, кажется, не работает с моим текущим компликером) Мы должны сделать дескриптор структурой, так как C не поддерживает классы.
Это дает нам базовый интерфейс C. Если вам нужен более полный пример, показывающий один из способов интеграции обработки исключений, то вы можете попробовать мой код на github: https://gist.github.com/mikeando/5394166
Теперь интересная часть гарантирует, что вы правильно получите все необходимые библиотеки C++, связанные в большую библиотеку. Для gcc (или clang) это означает, что выполняется только заключительная стадия связи с использованием g++.
-121--2043465-Я думаю, iPhone правит разработкой оборудования и программного обеспечения, андроид интересен, но слишком новый, симбиам умирает, потому что Nokia, окна переживут причину денег с bull € & € &, но они будут. iPhone слишком ограничительный и чертовски дорогой, но это thecoolest сейчас. Наконец я думаю, что для NeXT 2 года iPhone будет царить.
-121--2740759-Вместо совместного использования блокировки может потребоваться отдельный процесс, ответственный за сохранение блокировки файла. Чтобы начать ваш шаг чтения/изменения/записи, поток должен будет запросить этот центральный процесс блокировки через HTTP, сообщения или что угодно. Если запрос отклонен, поток перейдет в спящий режим, проснется и повторите попытку. В противном случае поток считывает/изменяет/записывает, а затем сообщает процессу блокировки, что снимает блокировку.
Вы захотите синхронизировать на каком-то объекте. Например:
synchronized(fileLockObject) {
readContentsFromFile(f);
modifyContentsFromFile(f);
writeFile(f);
}