Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Многопоточное програмирование.doc
Скачиваний:
3
Добавлен:
14.11.2019
Размер:
332.8 Кб
Скачать
  1. Структура DirCont использует свой собственный пул для имен директорий и файлов:

  2. struct DirCont {

  3. Mem_pool ownmp;

  4. sh_text name;

  5. hash_vec<sh_text, char> dirs;

  6. hash_vec<sh_text, unsigned long> files;

  7. DirCont(const ch_rng& nm) : name(nt(ownmp, nm)), dirs(101), files(1001)

  8. {}

};

Здесь мы имеем тот редкий случай, когда в одной точке приложения одновременно сходятся несколько объектов mem_pool, принадлежащих разным потокам:

    1. объект ownmp, принадлежащий соответствующей структуре mt.oldDir или mt.newDir

    2. привычный объект mp, являющийся временным личным объектом рабочего потока, создаваемым thread_pool-ом на время работы функции MainTask::proc()

Как следствие, doFindFiles() создает сохраняемые имена директорий и файлов с помощью ownmp:

void MainTask::doFindFiles(mem_pool& mp, data_queue&, Arg&, const FindFilesMsg&

msg)

{

int pref=msg.dir->name->size();

vector<sh_text> dirs;

for (dirs.push_back(msg.dir->name); dirs.size(); ) {

sh_dir shd=new_dir(mp, dirs.back());

dirs.pop_back();

for (dir::entry dent(mp); shd->find_next(dent); ) {

if (dent.name=="." || dent.name=="..") continue;

sh_text fname=shd->full_name(dent);

if (dent.isdir) dirs.push_back(fname);

assert(fname->size()>=pref+1);

int beg= (fname->begin()[pref]==pathSepr) ? pref+1 : pref;

sh_text name(nt(msg.dir->ownmp, fname->begin()+beg, fname->end()));

if (dent.isdir) msg.dir->dirs.insert(name, 0);

else msg.dir->files.insert(name, dent.size);

}

}

}

А doCompare() и doCopyFile() запоминают найденные имена (факт. ключи hash_vec<sh_text, ...>-ра) по ссылке, а не значению:

const sh_text& dir=dc1->dirs.key(i);

// ...

const sh_text& fil=dc1->files.key(i);

// ...

const sh_text& name=oldDir.files.key(msg.oldPos);

Т.к. сохранение по значению приведет к копированию объекта sh_ptr<text> и, как следствие, одновременному использованию ownmp несколькими рабочими потоками. Тем самым в программе появится ошибка синхронизации, т.е. та самая "великая и ужасная" race condition, непонятно когда и как проявляющаяся.

И если желаете, то в качестве неприятного, но весьма поучительного упражнения можно и в самом деле заменить ссылки на значения и попытаться ее отследить...

  1. Изменившийся файл может находиться достаточно глубоко в структуре сравниваемых поддиректорий, поэтому его копирование в директорию diff_dir/mod/... может потребовать предварительного создания недостающих промежуточных поддиректорий. Задача осложняется еще и тем, что подлежащие созданию поддиректории могут быть созданы параллельно работающими потоками в промежутке между временем обнаружения их отсутствия и попыткой их создать. Для эффективного решения данной проблемы приложение пробует сразу же создать несуществующий файл и только в случае ошибки выполняется попытка создания промежуточных директорий и повторная попытка создания файла:

  2. file fout(mp);

  3. if (!fout.open(msg.toName, file::wro, file::crt|file::trnc)) {

  4. make_dirs(mp, get_path(mp, msg.toName));

  5. fout.ex_open(msg.toName, file::wro, file::crt|file::trnc);

}

Обратите внимание, что для повторного создания файла вместо функции open() используется вызов ex_open(), автоматически возбуждающей исключения.