Хіба розумно замінити boost :: thread та boost :: mutex на c ++ 11 еквівалентів?


153

Мотивація: причина, чому я вважаю, це те, що мій геніальний керівник проекту вважає, що стимул - це ще одна залежність, і що це жахливо, тому що "ти від цього залежить" (я спробував пояснити якість підвищення, а потім через деякий час відмовився :( Менша причина, чому я хотів би це зробити, це те, що я хотів би вивчити функції + + 11, тому що люди почнуть писати в ньому код.

  1. Чи є зіставлення 1: 1 між #include<thread> #include<mutex>еквівалентами та збільшенням?
  2. Чи вважаєте ви хорошою ідеєю замінити прискорені речі на c ++ 11
    . Моє використання примітивне, але чи є приклади, коли std не пропонує, що сприяє? Або (богохульство) навпаки?

PS Я використовую GCC, щоб заголовки були.


46
Вказівки щодо кодування IMO Google багато в чому дурні ... Наприклад, наприклад. вони не дозволяють авто з C ++ 11 ... :)
NoSenseEtAl

5
Вказівки щодо цитування: [auto] перешкоджає читанню [тому що вона видаляє] перевірену надмірність (наприклад, назви типів), яка може бути корисною для читачів.
Андрій Томазос

31
for (auto it = v.begin () ... :)
NoSenseEtAl

15
@ AndrewTomazos-Fathomling: Дійсно? Особисто я не думаю, що я ніколи не піклувався про фактичний тип ітератора (ну, може, кілька разів), лише підтримувані операції ... Я б стверджував, що синтаксичне надмірність рідко добре подумати (DRY).
Grizzly

16
btw google змінив свої німі вказівки, тож нарешті вони дозволяють автоматично
NoSenseEtAl

Відповіді:


192

Існує кілька відмінностей між Boost.Thread і стандартною бібліотекою потоків C ++ 11:

  • Boost підтримує скасування потоку, C ++ 11 потоків - ні
  • C ++ 11 підтримує std::async, але Boost цього не робить
  • Boost має boost::shared_mutexблокування для читання чи одноразового запису. Аналогічно std::shared_timed_mutexдоступний тільки з C ++ 14 ( N3891 ), в той час якstd::shared_mutex доступний тільки з C ++ 17 ( N4508 ).
  • Час очікування C ++ 11 відрізняється від таймаутів Boost (хоча це незабаром має змінитися. Boost.Chrono було прийнято).
  • Деякі назви різні (напр boost::unique_future проти std::future)
  • Семантика передачі аргументів std::threadвідрізняється від boost::thread--- використання Boost boost::bind, що вимагає копіюючих аргументів. std::threadдозволяє типи, std::unique_ptrщо передаються лише для переміщення, такі, що передаються як аргументи. Завдяки використаннюboost::bind семантики заповнювачів, таких як _1у вкладених виразах зв'язування, теж може бути різною.
  • Якщо ви не явно не викликаєте join()або detach()тоді boost::threadоператор деструктора і призначення призначить виклик detach()об'єкта потоку, який буде знищений / призначений. З std::threadоб'єктом C ++ 11 це призведе до виклику доstd::terminate() та скасування програми.

Для уточнення пункту щодо параметрів, що рухаються, наступне дійсне C ++ 11 і передає право власності intна тимчасовий std::unique_ptrна параметр, f1коли запускається новий потік. Однак якщо ви користуєтеся, boost::threadто він не працюватиме, як він використовується boost::bindвнутрішньо, і std::unique_ptrне може бути скопійований. Також є помилка в бібліотеці потоків C ++ 11, забезпеченій GCC, що не дозволяє це працювати, як це використовується і std::bindв реалізації.

void f1(std::unique_ptr<int>);
std::thread t1(f1,std::unique_ptr<int>(new int(42)));

Якщо ви використовуєте Boost, ви, ймовірно, можете перейти на потоки C ++ 11 порівняно безболісно, ​​якщо ваш компілятор підтримує його (наприклад, останні версії GCC в Linux мають переважно повну реалізацію бібліотеки потоків C ++ 11, доступної в -std=c++0x режимі).

Якщо ваш компілятор не підтримує потоки C ++ 11, то, можливо, ви зможете отримати сторонню реалізацію, таку як Just :: Thread , але це все-таки залежність.


1
Існують окремі методи блокування / розблокування для читачів і письменників ( lock/ unlockдля письменників проти 'lock_shared / unlock_shared' для читачів). Кілька читачів можуть дзвонити lock_shared без блокування, доки ніхто з авторів не використовує його.
Дейв S

2
У shared_mutexдокументах знаходяться на boost.org/doc/libs/1_47_0/doc/html/thread / ... . Ви або заблокуйте mutex як спільний або ексклюзивний, а потім використовуєте відповідну функцію розблокування. Для цього також можна використовувати типи RAII ( shared_lockбере загальний замок читання lock_guardта unique_lockприймає ексклюзивний замок). Я намагався уточнити суть щодо типів, що рухаються лише для переміщення.
Ентоні Вільямс

3
Ще одна незначна річ, яка мене збудила : у прискоренні деструктор запущеної нитки відриває її ( boost.org/doc/libs/1_47_0/doc/html/thread/… ), тоді як у C ++ деструктор запущеної нитки викликає завершення () (FDIS 30.3.1.3)
Cubbi

3
У C ++ 11 try_scoped_lockфункціональність охоплюється std::unique_lock. Існує конструктор, який приймає мютекс і std::try_to_lock, а потім закликає try_lock()мутекс, а не lock(). Дивіться stdthread.co.uk/doc/headers/mutex/unique_lock/…
Ентоні Вільямс

4
Так, Boost.Thread набагато наблизився до стандарту C ++ 11, оскільки я написав це, насамперед завдяки роботі Вісенте Боте.
Ентоні Вільямс

24

std::threadв основному моделюється після boost::thread, з кількома відмінностями :

  • Неможливо скопіювати, що копіюються, одна ручка-карти-в-один-ос-нитка, семантика зберігається. Але ця нитка є рухомою, що дозволяє повернути нитку з заводських функцій і розмістити в контейнери.
  • Ця пропозиція додає скасування до boost::thread, що є суттєвим ускладненням. Ця зміна має великий вплив не тільки на потоки, але й на решту C ++ бібліотек для нарізки. Вважається, що ця велика зміна виправдана через користь.
    • Тепер деструктор потоку повинен викликати скасувати перед від'єднанням, щоб уникнути випадкового протікання дочірніх потоків при скасуванні батьківських потоків.
    • Тепер явний член від'єднання потрібен, щоб увімкнути від'єднання без скасування.
  • Поняття ручки ниток та ідентичності нитки були розділені на два класи (вони є одним класом у boost::thread). Це для спрощення маніпуляції та зберігання ідентичності потоку.
  • Можливість створення ідентифікатора потоку, який гарантовано порівняно рівний жодному іншому об'єднаному потоку, не додано ( boost::threadцього немає). Це зручно для коду, який хоче знати, чи виконується він тим же потоком, що і попередній виклик (рекурсивні мутекси - конкретний приклад).
  • Існує "задня дверцята", щоб отримати ручку нативного потоку, щоб клієнти могли маніпулювати потоками, використовуючи базову ОС, якщо потрібно.

Це з 2007 року, тому деякі пункти більше не діють: функція boost::threadмає native_handleзараз, і, як зазначають коментатори, std::threadбільше не має скасування.

Я не зміг знайти значних відмінностей між boost::mutexта std::mutex.


2
std::threadне має скасування; це boost::threadте, що робить!
Ентоні Вільямс

@Anthony Ви впевнені, що не маєте interrupt()на увазі boost :: thread? Також видається, що це оригінальна пропозиція, яка змінювалася з 2007 року.
Алекс Б

4
Так, скасування прискорення називається "перериванням". Так, це стара пропозиція. Останній публічний проект стандарту C ++ 11 (який включає бібліотеку ниток) - open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
Ентоні Вільямс

6

Є одна причина, на яку не мігрувати std::thread.

Якщо ви використовуєте статичне посилання, std::threadстає непридатним через ці помилки / функції gcc:

А саме, якщо ви зателефонували std::thread::detachабо std::thread::joinце призведе до винятку чи збоїв, boost::threadв цих випадках все нормально.


Я бачу, що одна помилка не підтверджена, а інша - НЕВЕРІЛЬНА, з коментарем сказано, що репортер повинен був пов’язатись проти libpthread.a. Ви абсолютно впевнені в тому, що говорите?
einpoklum

1
@einpoklum, ви повинні мати можливість змусити його працювати, використовуючи Wl,--whole-archive -lpthread -Wl,--no-whole-archive, див. цю відповідь, наприклад, stackoverflow.com/a/23504509/72178 . Але це не дуже простий спосіб зв'язатись, libpthread.aа також вважається поганою ідеєю.
ks1322

4
Чи можемо ми припустити, що ці помилки виправлені, оскільки це зараз 2016 рік? Помилки були опубліковані у 2012 році та з gcc 4.9.2, він офіційно підтримує C ++ 11, тому ми не можемо скаржитися на C ++ 11 перед офіційною підтримкою.
Сплеск

6

Корпоративна справа

Якщо ви пишете програмне забезпечення для підприємства, яке потребує роботи на помірній та великій різноманітності операційних систем і, отже, будувати з різними компіляторами та версіями компіляторів (особливо відносно старими) на цих операційних системах, моя пропозиція - не триматися осторонь С ++ 11 загалом. Це означає, що ви не можете використовувати std::thread, і я б рекомендував використовувати boost::thread.

Основний / технічний запуск

Якщо ви пишете для однієї або двох операційних систем, ви точно знаєте, що вам буде потрібно коли-небудь будувати за допомогою сучасного компілятора, який в основному підтримує C ++ 11 (наприклад, VS2015, GCC 5.3, Xcode 7), і ви ще не є Залежно від бібліотеки підвищення, тоді std::threadможе бути хорошим варіантом.

Мій досвід

Я особисто частковий до загартованих, широко використовуваних, дуже сумісних, дуже послідовних бібліотек, таких як "підсилення" проти дуже сучасної альтернативи. Особливо це стосується складних предметів програмування, таких як нарізка різьби. Крім того, я давно переживав великий успіх у boost::thread(і в цілому поштовх) у широкому наборі середовищ, компіляторів, моделей з нарізками і т. Д. Коли мій вибір, я вибираю підвищення.


1
@UmNyobe Він прав. Багато реалізацій потоків C ++ 11 настільки зламані, я здивований, що люди навіть розглядають можливість його використання.
StaceyGirl


1

Стосовно std :: shared_mutex додано в C ++ 17

Інші відповіді тут дають дуже хороший огляд відмінностей загалом. Однак існує кілька проблем, std::shared_mutexякі вирішують цей приріст.

  1. Оновлені мутики. Вони відсутні у std::thread. Вони дозволяють читачеві перейти на письменника, не дозволяючи жодним іншим письменникам зайти до вас . Вони дозволяють виконувати такі дії, як попередня обробка великих обчислень (наприклад, перевстановлення структури даних) у режимі читання, а потім оновлення до запису, щоб застосувати повторний дексес, утримуючи лише блокування запису протягом короткого часу.

  2. Справедливість. Якщо ви постійно працюєте з читанням std::shared_mutex, ваші автори будуть заблоковані нескінченно. Це тому, що якщо прийде інший читач, їм завжди буде надано пріоритет. З boost:shared_mutex, всім потокам з часом буде надано пріоритет. (1) Ні читачі, ні письменники не будуть голодувати.

Проблема цього полягає в тому, що якщо у вас дуже висока пропускна спроможність, без простоїв і дуже великої суперечки, std::shared_mutexвона ніколи не працюватиме для вас без ручного побудови системи пріоритетів над нею. boost::shared_mutexбуде працювати з коробки, хоча вам, можливо, доведеться повозитися з нею в певних випадках. Я б стверджував, що std::shared_mutexповедінка є прихованою помилкою, яка чекає трапитися в більшості кодів, які її використовують.

(1) Фактичний алгоритм використовує на основі ОС планувальник потоків. На мій досвід, коли читання насичене, в Windows є довші паузи (при отриманні блокування запису), ніж в OSX / Linux.


0

Я намагався використовувати shared_ptr від std замість boost, і я дійсно виявив помилку в реалізації gcc цього класу. У моєму додатку виходило з ладу через деструктор, який викликався двічі (цей клас повинен бути безпечним для потоків і не повинен створювати таких проблем). Після переходу до boost :: shared_ptr всі проблеми зникли. Поточні реалізації C ++ 11 ще не зрілі.

Boost також має більше функцій. Наприклад, заголовок у std-версії не забезпечує серіалізатор для потоку (тобто cout << тривалість). Boost має багато бібліотек, які використовують свої власні тощо еквіваленти, але не співпрацюють із std версіями.

Підводячи підсумок - якщо у вас вже є додаток, написане за допомогою boost, безпечніше зберігати код таким, який він є, замість того, щоб докладати певних зусиль для переходу до стандарту C ++ 11.


4
shared_ptrДеструкція не повинні бути поточно-, це невизначене поведінку , щоб мати одну нитку з доступом об'єкт , а інший потік руйнує його. Якщо ви думаєте, що знайшли помилку в GCC's shared_ptr, будь ласка, повідомте про це , інакше, за імовірністю, ви неправильно використовуєте.
Джонатан Уейклі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.