Pull to refresh

Comments 50

А давайте просто скажем одно ключевое слово — RAII, и не просто дадим людям рыбу, но и научим её ловить раз и навсегда?
Спасибо, добавил в начале упоминание об этом.
Конечно. Но использовать QT в качестве коллекции велосипедов, как мне кажется, не очень разумно. Не особо представляю себе причины, которые могут побудить человека использовать QT в демоне, например.
А что с QT в этом смысле не так?
Размер программы, в первую очередь.
Да и ни к чему тянуть сторонние библиотеки ради пары макросов и классов.
>Размер программы, в первую очередь.

$ cat main_stl.cpp 
#include <string>
#include <iostream>

int main(int argc, char* argv[]) {
	std::string s = "Hello, world!";
	std::cout << s << std::endl;
	return 0;
}

$ cat main_qt.cpp 
#include <QString>
#include <QDebug>

int main(int argc, char* argv[]) {
	QString s = "Hello, world!";
	qDebug() << s;
	return 0;
}

$ cat strings_qt.pro 
TARGET   = strings_qt
SOURCES  = main_qt.cpp

$ qmake && make 1>/dev/null 2>1
$ g++ main_stl.cpp -o strings_stl
$ ls -l strings_*
-rwxr-xr-x 1 mikhail mikhail 9125 2009-11-13 15:45 strings_qt
-rwxr-xr-x 1 mikhail mikhail 9364 2009-11-13 15:45 strings_stl

$ strip strings_*
$ ls -l strings_*
-rwxr-xr-x 1 mikhail mikhail 5692 2009-11-13 15:46 strings_qt
-rwxr-xr-x 1 mikhail mikhail 5684 2009-11-13 15:46 strings_stl

Вы какой именно размер имели в виду? :)

>Да и ни к чему тянуть сторонние библиотеки ради пары макросов и классов.

Сторонние библиотеки для того и созданы ;)
Что касается Qt — то libQtCore весит 2 мегабайта. Как по мне — вполне приемлемый размер (для того, что она несёт внутри).
UFO just landed and posted this here
А почему бы не построить некоторые моменты демона на томже Qt, проблемы в этом не вижу. Знаю пример решения задачи разработки демона под FreeBSD (тз такое), но человек владел разработкой только под WIN, а разбираться в тонкостях UNIX времени не было. На помощь пришел Qt, что облегчило разработку в разы:
— любимыая, удобная IDE;
— интуитивно понятная архитектура библиотеки;
— все необходимые абстракции от платформы.

Как итог все счастливы и довольны.
Ну, если надо срочно, а опыта с никсами нет, то может и осмысленно. Но в обычном случае это все-таки из пушки по воробьям.
Да, есть что-то похожее, но:
— нужно подключать стороннюю библиотеку
— не понял исходя из текста, каким образом в упомянутых классах я могу выбрать объект синхронизации: мютекс или критическая секция (Win).
— слишком «много букв» :)

Там шаблон на шаблоне и шаблоном погоняет. Какой объект ему подставишь туда, такой и будет. И никаких системных типов, все через объекты той же библиотеки.
Кстати, подключать там вроде бы ничего особо не надо. Половина boost — это только .h, линковать там что-то приходится не так уж часто, особенно в таких вот «оберточных» частях.
UFO just landed and posted this here
А что бы вы хотели услышать?
В STL есть очень удобный класс-шаблон std::auto_ptr<>, освобождающий память по указателю при уничтожении объекта этого класса.
Который объявлен deprecated в c++0x. Вместо auto_ptr следует использовать unique_ptr, так как он поддерживает только явные операции с семантикой смены владения объектом.
UFO just landed and posted this here
В MSDN по этому поводу пишут кратко и емко.
Я не сказал бы, что имеет смысл действительно ипользовать эту штуковину в реальных проектах, ведь есть множество уже готовых и заведомо лучших решений.
Однако, большое спасибо за статью об устройстве мьютексов.
Проблема: макрос SCOPE_LOCK_MUTEX не получится использовать два раза в одном и том же блоке.
обычно это и не нужно
UFO just landed and posted this here
UFO just landed and posted this here
inline для метода, объявленного внутри класса вообще не нужно, оно там подразумевается.
UFO just landed and posted this here
ISO 14882, 7.1.2.3:

A function defined within a class definition is an inline function. The inline specifier shall not appear on a block scope function declaration.
UFO just landed and posted this here
Далеко не всегда это можно так просто решить. Вот вы определите функцию в файле code.cc, а в заголовке оставите только forward declaration. Тут может помочь только whole program optimization при условии что компилируются сразу все файлы исходного кода вместе. А если перенесёте функцию из code.cc в заголовочный файл, то опишете её как static, иначе получите одну и ту же функцию определённую несколько раз в разных объектниках. Теперь если такой заголовок включить в code2.cc, в котором именно эта функция не нужна, но нужна какая-то другая, то получим warning от компилятора про неиспользуемую функцию.
UFO just landed and posted this here
code.h: void f() {...}
code2.cc: #include «code.h»
code3.cc: #include «code.h»

компилируем
code2.cc ->code2.o
code3.cc ->code3.o

линкуем
code2.o + code3.o = error, f() два раза определена
Поправьте пожалуйста первый кусок кода. Там вместо CAutoMutex тот же CMutexLock.
еще неплохо бы дописать про рекурсивные мьютексы тогда.
А именно

f()
{
AutoMutex m;
f();
}

рекурсивный мьютекс — сможет зайти сам в себя, нерекурсивный нет.

зы. boost::mutex::scoped_lock lock(mutex); тоже кстати решает эту задачу
В Windows мютексы по умолчанию рекурсивные, а в Unix — нерекурсивные.
Чтобы в Unix сделать мютекс рекурсивным, необходимо установить соответствующий флаг при инициализации. Класс CAutoMutex выглядел бы так (проверки возвращаемых значений не показаны для компактности):
class CAutoMutex
{
  pthread_mutex_t m_mutex;

  CAutoMutex(const CAutoMutex&);
  CAutoMutex& operator=(const CAutoMutex&);

public:
  inline CAutoMutex()
  {
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&m_mutex, &attr);
    pthread_mutexattr_destroy(&attr);
  }
  inline ~CAutoMutex()
  {
    pthread_mutex_destroy(&m_mutex);
  }
  inline pthread_mutex_t& get()
  {
    return m_mutex;
  }
};


* This source code was highlighted with Source Code Highlighter.

а как в винде сделать нерекурсивный?
полностью аналогичным образом можно использовать семафор с максимальным счетчиком 1, он будет нерекурсивным.
HANDLE sem_1 = CreateSemaphore(NULL, 1, 1, NULL)

> При написании многопоточных приложений…

Виндовые мьютексы для синхронизации тредов — не из пушки ли по воробьям? Критической секции обычно хватает за глаза.
> Ниже рассматривается работа с мютексами в Windows и Unix
И где там Unix?
1. Зачем каждый раз писать get в auto locker-e? Можно сделать чтобы он принимал не только handle но и объект мютекс вами написаный.
2. Зачем делать #define не понятно. Какая разница что запоминать, как класс автолокера называется или как макрос пишется?
Для элегантности еще убрать макрос хорошо было бы.
Ну и упоминание про Unix как-то не к месту, позиксовые мютексы отличаются в обработке, заметно.
Присоединяюсь ко всем остальным по поводу той мысли, что не надо строить велосипеды, но спешу добавить, что порой, сделать велосипед — это единственный способ разобраться в чем-либо. Совет автору статьи — почитайте Рихтера «Windows via C/C++» и скачайте примеры кода к этой книге, там уже большинство всего необходимого реализовано.
>спешу добавить, что порой, сделать велосипед — это единственный способ разобраться в чем-либо.
полностью согласен

Статья в себе сочетает отрывки из Стивенсова про мьютексы и принципа Александреску: один ресурс — один класс, Конструктор — захват ресурса, деструктор — освобождение. Но в целом — хорошее пособие для начинающего в многопоточности… Мне статья понравилась, жаль примеров нет или тестов, Это совет автору на будущее.

что касается замечания по использованию сторонних библиотек — не всегда рационально тащить из-за одной-двух компонент громадную стороннюю библиотеку. Однако, возможности таких библиотек как STL & Boost надо использовать максимально.
А я правильно понял, что рекурсивные мьютексы отличаются от рекурсивных тем что:
— Рекурсивный может захватываться одним и темже потоком много раз, и никого не пустит, пока не будет отдан потоком столько же раз. (типа захват ++а, релиз --а, пускает когда а==0)
— А нерекурсивный можно захватывать тоже сколько угодно раз, но позволит всем ходить он как только его отпустят ( (типа захват ++а, релиз а=0, пускает когда а==0)
?
Про рекурсивный вы поняли верно, а с нерекурсивным дело обстоит иначе: при повторной попытке захватить нерекурсивный мютекс в одном потоке возникнет deadlock.
Спасибо. Собственно это и был вопрос, с виндовыми я собаку съел (ведь если их не отпустить n раз то тоже дедлок). Собака на 2х концах :)
На память себе, и для нагугливших эту статью раньше остальных: Критическая секция (critical section) под виндой делает то же самое, что и mutex, но лишь в пределах одного процесса и быстрее. А mutex это получается глобальный объект системы для межпроцессного взаимодействия. см. также Mutex или CRITICAL_SECTION? В каких случаях что использовать?
Sign up to leave a comment.

Articles