Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Аналог SleepConditionVariableCS(). В чем ошибка? / 3 сообщений из 3, страница 1 из 1
29.10.2016, 17:01
    #39336961
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Аналог SleepConditionVariableCS(). В чем ошибка?
Пытался откомпилировать ZeroMQ но наткнулся на проблемы запуска под XP.

Они там задействовали виндовые Condition Variable. Надо переписать SleepConditionVariableCS() и WakeAllConditionVariable()
Исходный код такой ( тут целиком ):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
    class condition_variable_t    {
	CONDITION_VARIABLE cv;

	inline int wait (mutex_t* mutex_, int timeout_ ) {
			int rc = SleepConditionVariableCS(&cv, mutex_->get_cs(), timeout_);
			if (rc != 0)	return 0;

			rc = GetLastError();
			if (rc != ERROR_TIMEOUT) win_assert(rc);

			errno = EAGAIN;
			return -1;
	}

        inline void broadcast () {
			WakeAllConditionVariable(&cv);
        }
    }


mutex_t класс-обертка над CRITICAL_SECTION
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
    class mutex_t
    {
    public:
        inline mutex_t ()
        {
            InitializeCriticalSection (&cs);
        }

        inline ~mutex_t ()
        {
            DeleteCriticalSection (&cs);
        }

        inline void lock ()
        {
            EnterCriticalSection (&cs);
        }

        inline bool try_lock ()
        {
            return (TryEnterCriticalSection (&cs)) ? true : false;
        }

        inline void unlock ()
        {
            LeaveCriticalSection (&cs);
        }

        inline CRITICAL_SECTION* get_cs()
        {
            return &cs;
        }

    private:

        CRITICAL_SECTION cs;

        //  Disable copy construction and assignment.
        mutex_t (const mutex_t&);
        void operator = (const mutex_t&);
    };


Переписал так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
    class condition_variable_t {
	std::condition_variable cv;
	std::mutex mtx;

        inline int wait (mutex_t* mutex_, int timeout_ ) {
			std::unique_lock<std::mutex> lck(mtx);
			mutex_->unlock(); // LeaveCriticalSection (mutex_->get_cs());
			int res = 0;
			switch(timeout_) {
				case INFINITE: // -1 ждем без указания времени
					cv.wait(lck);
					break;

				case 0:
					break;

				default: // Сюда никогда не заходит. Все вызовы с -1 и 0
					if (cv.wait_for(lck, std::chrono::milliseconds(timeout_)) == std::cv_status::timeout) {
						// По истечению таймаута SleepConditionVariableCS() == 0
						errno = EAGAIN;
						res = -1;
					}
			}
			mutex_->lock();  // EnterCriticalSection (mutex_->get_cs());
			return res;
	}

        inline void broadcast () {
			std::unique_lock<std::mutex> lck(mtx);
			cv.notify_all();
        }
    }



Как понял SleepConditionVariableCS() атомарно разблокирует CS и виснет в в ожидании WakeAllConditionVariable() или истечения времени. По выходу опять блокирует CS.

Я по сути тоже самое реализовал std::unique_lock<std::mutex> lck(mtx); блокирует мутекс при входе и освобождает при выходе, также мутекс свободен пока висит на cv.wait().

Мой код работает в ненагруженных тестах, но как только дал реальную нагрузку (1000 соединений с интенсивным обменом) - так периодически затыкается. Просто виснет и все.

Подозреваю что я что-то еще не учел, только что? Еще какие-то особенности SleepConditionVariableCS() ?
...
Рейтинг: 0 / 0
30.10.2016, 12:58
    #39337247
locked
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Аналог SleepConditionVariableCS(). В чем ошибка?
Dima T,

все локи должны захватываться в одном порядке. В твоем примере в разных порядках. При большой нагрузке может случится deadlock.
...
Рейтинг: 0 / 0
30.10.2016, 16:01
    #39337340
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Аналог SleepConditionVariableCS(). В чем ошибка?
Спасибо за мысль. Починил. Добавил освобождение мутекса перед захватом критической секции.
Так работает и не виснет:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
			std::unique_lock<std::mutex> lck(mtx); // захватываем mtx
			mutex_->unlock(); //  // освобождаем mutex_ 
			int res;
			switch (timeout_) {
			case INFINITE: // -1 ждем без указания времени
				cv.wait(lck); // освобождаем mtx и висим на cv
				break;        // захватываем mtx при выходе из cv.wait()

			case 0: // эмулируем истечение таймаута
				errno = EAGAIN;
				res = -1;
				break;

			default: // Сюда никогда не заходит. Все вызовы с -1 и 0
				if (cv.wait_for(lck, std::chrono::milliseconds(timeout_)) == std::cv_status::timeout) {
					// По истечению таймаута SleepConditionVariableCS() == 0
					errno = EAGAIN;
					res = -1;
				} else {
					res = 0;
				}
			}
			lck.unlock(); // освобождаем mtx
			mutex_->lock(); // захватываем mutex_
			return res;



Непонятно зачем вызывать с таймаутом 0, пытался понять по исходникам - не понял в чем магия.
Поэтому сделал эмуляцию (case 0) в итоге тест стал быстрее: 2.4 сек, против 4.3 сек. без эмулятора (case 0).
Кстати родной код с SleepConditionVariableCS() с такой же скоростью отрабатывал - 4,3 сек.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Аналог SleepConditionVariableCS(). В чем ошибка? / 3 сообщений из 3, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]