у меня проблема. Я хочу использовать мьютекс для моей программы. Итак, что происходит, это:
я строю объект, который содержит std :: timed_mutex. при создании этот объект блокирует мьютекс, потому что он должен быть разблокирован позже. тот же поток, который создал мьютекс, теперь должен ждать этого мьютекса, пока какой-то другой поток работает в фоновом режиме. присоединение к потоку не вариант.
class A{
std::timed_mutex mutex;
A(){
mutex.lock();
}
bool waitForIt(int timeout){
if(mutex.try_lock_for(std::chrono::milliseconds(timeout))){
mutex.unlock();
return true;
}else{
return false;
}
}
}
при вызове waitForIt из того же потока программа просто проходит и мгновенно получает ложное значение, полностью игнорируя время ожидания (да, оно предназначено для разблокирования мьютекса впоследствии. Оно должно имитировать что-то вроде события, чтобы каждый ожидающий поток проходил)
так в документация он говорит, что этот мьютекс имеет нерекурсивное поведение. но тестирование показало, что, например, я могу использовать .lock () несколько раз из одного потока без блокировки. я также могу использовать try_lock_for несколько раз, и каждый раз получаю правду !!! если я однажды использую блокировку перед try_lock_fors, я всегда получаю false. к сожалению, мне нужно что-то, что также блокирует тот же поток, который заблокировал мьютекс. и я понятия не имею, что использовать. Я программирую на Linux, кстати. так может есть нативное решение?
Также я не нашел семафора в std libs.i, чтобы использовать его вместо мьютекса. использование моей собственной реализации было бы возможно, но я не знаю, как сделать свой собственный семафор. есть идеи?
поскольку люди, кажется, не понимают, что это не так просто:
class IObservable : public IInterface{
private:
std::list<std::shared_ptr<IObserver>> observers;
public:
virtual ~IObservable(){}
void AddObserver(std::shared_ptr<IObserver> observer);
void RemoveObserver(std::shared_ptr<IObserver> observer);
void ClearObservers();
void TellCompleted(bool wasCanceled = false, std::shared_ptr<void> status = 0);
TYPEIDHASHFUNC(IObservable)
};
IObservable — это то, к чему потоки могут добавлять наблюдателей. вещь, производная от IObservable, вызывает метод TellCompleted в конце своих действий.
class IObserver : public IInterface{
public:
virtual ~IObserver(){}
virtual CompleteResult Complete(bool wasCanceled, std::shared_ptr<void> status) = 0;
virtual bool WaitForCompletion(int timeoutInMs) = 0;
virtual bool IsCompleted() const = 0;
virtual bool WasCanceled() const = 0;
virtual std::shared_ptr<void> GetStatus() const = 0;
virtual void Reset() = 0;
TYPEIDHASHFUNC(IObserver)
};
IObserver — это наблюдатель, который может быть добавлен в IObservable. если IObservable завершает, метод Complete вызывается для каждого наблюдателя, который был добавлен к наблюдаемой
class BasicObserver : public IObserver{
private:
bool isCompleted;
bool wasCanceled;
CompleteResult completeResult;
std::shared_ptr<void> status;
std::timed_mutex mutex;
public:
BasicObserver(CompleteResult completeResult);
~BasicObserver();
CompleteResult Complete(bool wasCanceled, std::shared_ptr<void> status);
bool WaitForCompletion(int timeoutInMs);
bool IsCompleted() const;
bool WasCanceled() const;
std::shared_ptr<void> GetStatus() const;
void Reset();
TYPEIDHASHFUNC(BasicObserver)
};
это одна из реализаций наблюдателя. он содержит мьютекс и реализует WaitForCompletion с таймаутом. WaitForCompletion должен заблокироваться. когда завершается вызов, его мьютекс должен быть разблокирован. когда тайм-аут работает, WaitForCompletion возвращает false
BasicObserver::BasicObserver(CompleteResult completeResult):
isCompleted(false),
wasCanceled(false),
completeResult(completeResult)
{
std::thread createThread([this]{
this->mutex.lock();
});
createThread.join();
}
BasicObserver::~BasicObserver(){
}
CompleteResult BasicObserver::Complete(bool wasCanceled, std::shared_ptr<void> status){
this->wasCanceled = wasCanceled;
this->status = status;
isCompleted = true;
mutex.unlock();
return completeResult;
}
bool BasicObserver::WaitForCompletion(int timeoutInMs){
std::chrono::milliseconds time(timeoutInMs);
if(mutex.try_lock_for(time)){
mutex.unlock();
return true;
}else{
return false;
}
}
bool BasicObserver::IsCompleted() const{
return isCompleted;
}
bool BasicObserver::WasCanceled() const{
return wasCanceled;
}
std::shared_ptr<void> BasicObserver::GetStatus() const{
return status;
}
void BasicObserver::Reset(){
isCompleted = false;
wasCanceled = false;
status = 0;
std::chrono::milliseconds time(250);
mutex.try_lock_for(time); //if this fails it might be already resetted
}
// редактирование: решено с помощью семафора (sem_t из semaphore.h)
Вы могли бы использовать condation_variable
конкретно Подожди пока или же ждать.
Я хотел бы рассмотреть редизайн вашей структуры блокировки.
Почему бы не удерживать блокировку основным потоком, а когда происходит событие x, вы разблокируете его. Если вам нужно на какое-то время заблокировать, я бы просто заставил поток спать.
Пусть все рабочие потоки, блокирующие мьютекс, попытаются получить блокировку, если они должны работать одновременно, попросите их немедленно снять блокировку, как только они ее получат.
возможно использовать второй мьютекс для эмуляции события х.
я хочу установить блокировку из потока 1, а затем запустить поток 2, который
что-то делает (в этом случае ждите ввода от оборудования), а затем
ждать мьютекса в потоке 1. поток 2 затем разблокирует мьютекс, когда я
нажмите переключатель на оборудовании. я использую какой-то наблюдатель
шаблон. так что у меня есть что-то заметное, куда я добавляю наблюдателя (в
в этом случае класс А является наблюдателем). в какой-то момент наблюдаемое
сообщает всем добавленным наблюдателям, что оно выполнило свою задачу и, таким образом, открывает
мьютекс. как у нас есть оборудование здесь может быть, что оборудование
зависает или датчик не работает. так что мне нужен тайм-аут. — fredlllll 3
минут назад
РЕДАКТИРОВАТЬ — Может быть, это будет работать?
Удерживайте блокировку в потоке 1, после того как поток 2 получит входной блок для этой блокировки. Пусть поток 1 снимет блокировку по истечении времени ожидания, может, немного поспит, чтобы пропустить потоки, а затем снова захватить блокировку. Пусть поток 2 освободит блокировку 1, затем начнет блокировку второго мьютекса после получения мьютекса 1, пусть аппаратный переключатель разблокирует мьютекс 2, который заставит поток 2 заблокировать мьютекс 2, а затем разблокировать мьютекс 2. Пусть аппаратный переключатель снова получит мьютекс 2.