powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Аналог SleepConditionVariableCS(). В чем ошибка?
3 сообщений из 3, страница 1 из 1
Аналог SleepConditionVariableCS(). В чем ошибка?
    #39336961
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пытался откомпилировать 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
Аналог SleepConditionVariableCS(). В чем ошибка?
    #39337247
locked
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima T,

все локи должны захватываться в одном порядке. В твоем примере в разных порядках. При большой нагрузке может случится deadlock.
...
Рейтинг: 0 / 0
Аналог SleepConditionVariableCS(). В чем ошибка?
    #39337340
Dima 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.
			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
3 сообщений из 3, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Аналог SleepConditionVariableCS(). В чем ошибка?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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