Страниц: [1] 2 3 ... 10
 1 
 : Декабря 06, 2018, 09:20:40 pm 
Автор qnx_user - Последний ответ от qnx_user
_disable() и _enable() - точно лишние.
Но есть потенциальная опасность (особенно для QNX 4) - если в memcpy() попадут кривые аргументы и умрёт вызвавший её процесс (по SIGSEGV) то всё остальное встанет наглухо. Так что нужно городить некую отпускалку.

Спасибо, об этом я не подумал. От _disable() и _enable() отказался.

 2 
 : Декабря 05, 2018, 01:30:32 pm 
Автор qnx_user - Последний ответ от PoP
_disable() и _enable() - точно лишние.
Но есть потенциальная опасность (особенно для QNX 4) - если в memcpy() попадут кривые аргументы и умрёт вызвавший её процесс (по SIGSEGV) то всё остальное встанет наглухо. Так что нужно городить некую отпускалку.

 3 
 : Декабря 05, 2018, 12:57:47 pm 
Автор qnx_user - Последний ответ от da-nie
Цитировать
и дополнительным отключением прерываний на момент копирования,

А зачем? Вы же из прерывания не работаете с разделяемой памятью? А так - у вас блокировка на семафоре. В принципе, насколько мне известно, так с этой памятью и работают.

Я, например, делал с такими обёртками:

cmmap.h
Код:
#ifndef C_MMAP_H
#define C_MMAP_H
//****************************************************************************************************
//класс работы с mmap
//****************************************************************************************************

//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <sys/mman.h>
#include <stdint.h>
#include <stddef.h>

//****************************************************************************************************
//класс работы с mmap
//****************************************************************************************************
class CMMAP
{
 private:
  uint8_t *SharedMemoryPtr;//указатель на блок памяти
  size_t Len;
 public:
  //конструктор
  CMMAP(void *add,size_t len,int prot,int flags,int fildes,off_t offr)
  {
   Len=len;
   void *ptr=mmap(add,len,prot,flags,fildes,offr);
   SharedMemoryPtr=NULL;
   if (ptr!=MAP_FAILED) SharedMemoryPtr=reinterpret_cast<uint8_t*>(ptr);  
  }
  //деструктор
  ~CMMAP()
  {
   if (SharedMemoryPtr!=NULL) munmap(SharedMemoryPtr,Len);
  }
  //получить адрес памяти
  uint8_t* GetPtr(void)
  {
   return(SharedMemoryPtr);
  }
  //узнать, выполнено ли подключение к памяти
  bool IsCreated(void)
  {
   if (SharedMemoryPtr!=NULL) return(true);
   return(false);
  }
};
#endif

craiicsemaphore.h
Код:
#ifndef C_RAII_CSEMAPHORE_H
#define C_RAII_CSEMAPHORE_H

//====================================================================================================
//описание
//====================================================================================================

//Класс RAII для работы с семафором

//====================================================================================================
//подключаемые библиотеки
//====================================================================================================

#include "csemaphore.h"

//====================================================================================================
//класс RAII для семафора
//====================================================================================================
class CRAIICSemaphore
{
 private:
  CSemaphore *cSemaphore_Ptr;//указатель на семафор
  bool Locked;//состояние семафора
 public:
  CRAIICSemaphore(CSemaphore *cSemaphore_Set_Ptr)//конструктор
  {
   Locked=false;
   if (cSemaphore_Set_Ptr==NULL) return;
   cSemaphore_Ptr=cSemaphore_Set_Ptr;
   Lock();
  }
  ~CRAIICSemaphore()
  {
   if (cSemaphore_Ptr==NULL) return;
   Unlock();
  }
  //заблокировать
  void Lock(void)
  {
   if (cSemaphore_Ptr==NULL) return;
   if (Locked==true) return;
   cSemaphore_Ptr->Lock();
   Locked=true;
  }
  //разблокировать
  void Unlock(void)
  {
   if (cSemaphore_Ptr==NULL) return;
   if (Locked==false) return;
   cSemaphore_Ptr->Unlock();
   Locked=false;
  }
};

#endif

csemaphore.h
Код:
#ifndef C_SEMAPHORE_H
#define C_SEMAPHORE_H
//****************************************************************************************************
//класс работы с семафором
//****************************************************************************************************

//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <stdio.h>

//****************************************************************************************************
//класс работы с семафором
//****************************************************************************************************
class CSemaphore
{
 private:
  sem_t *Semaphore;
 public:
  //конструктор  
  CSemaphore(const char *name,int oflag,mode_t mode,unsigned int value)
  {
   Semaphore=sem_open(name,oflag,mode,value);
  }
  //деструктор
  ~CSemaphore()
  {
   if (Semaphore!=SEM_FAILED) sem_close(Semaphore);
   //sem_unlink(SHARED_MEMORY_OBJECT_NAME);//уничтожение объекта семафора (можно не делать, чтобы его не потерять в других процессах)
  }
  //получить семафор
  sem_t* GetHandle(void)
  {
   return(Semaphore);
  }
  //узнать, создан ли семафор
  bool IsCreated(void)
  {
   if (Semaphore!=SEM_FAILED) return(true);
   return(false);
  }
  //заблокировать семафор
  void Lock(void)
  {
   if (IsCreated()==false) return;  
   sem_wait(Semaphore);
  }
  //разблокировать семафор
  void Unlock(void)
  {
   if (IsCreated()==false) return;  
   sem_post(Semaphore);
  }
};
#endif

cshm.h
Код:
#ifndef C_SHM_H
#define C_SHM_H
//****************************************************************************************************
//класс работы с дескриптором разделяемой памяти
//****************************************************************************************************

//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <sys/mman.h>
#include <stdint.h>
#include <stddef.h>
#include <fcntl.h>

#include <stdio.h>
//****************************************************************************************************
//класс работы с дескриптором разделяемой памяти
//****************************************************************************************************
class CShM
{
 private:
  int SharedMemory;//дескриптор разделяемой памяти
 public:
  //конструктор
  CShM(const char *name,int oflag,mode_t mode)
  {
   SharedMemory=shm_open(name,oflag,mode);
  }
  //деструктор
  ~CShM()
  {
   if (SharedMemory>=0) close(SharedMemory);
   //shm_unlink(SHARED_MEMORY_OBJECT_NAME);//уничтожение объекта разделяемой памяти (можно не делать, чтобы её не потерять в других процессах)
  }
  //получить дескриптор разделяемой памяти
  int GetHandle(void)
  {
   return(SharedMemory);
  }
  //узнать, выполнено ли подключение к памяти
  bool IsCreated(void)
  {
   if (SharedMemory>=0) return(true);
   return(false);
  }
};
#endif

А дальше я делаю так (класс CUniquePtr - самодельный "умный" указатель - в 6.3 у меня штатного в stl нет):

Код:
static const std::string SHARED_MEMORY_OBJECT_NAME="/ipk_model_shared_memory";//имя разделяемой памяти
static const std::string SEMAPHORE_OBJECT_NAME="/ipk_model_semaphore";//имя семафора
static const uint32_t SHARED_MEMORY_OBJECT_SIZE=1024;//размер разделяемой области памяти

CUniquePtr<CShM> cUniquePtr_CShM;//указатель на дескриптор разделяемой памяти
CUniquePtr<CMMAP> cUniquePtr_CMMAP;//указатель на разделяемую память
CUniquePtr<CSemaphore> cUniquePtr_CSemaphore;//указатель на семафор  

//создаём разделяемую память
cUniquePtr_CShM.Set(new CShM(SHARED_MEMORY_OBJECT_NAME.c_str(),O_CREAT|O_RDWR,S_IRWXO|S_IRWXG|S_IRWXU));
if (cUniquePtr_CShM.Get()->IsCreated()==true)
{
 if (ftruncate(cUniquePtr_CShM.Get()->GetHandle(),SHARED_MEMORY_OBJECT_SIZE+1)>=0)
 {
  cUniquePtr_CMMAP.Set(new CMMAP(0,SHARED_MEMORY_OBJECT_SIZE+1,PROT_WRITE|PROT_READ,MAP_SHARED,cUniquePtr_CShM.Get()->GetHandle(),0));
 }
}
 //создаём семафор
 cUniquePtr_CSemaphore.Set(new CSemaphore(SEMAPHORE_OBJECT_NAME.c_str(),O_CREAT|O_RDWR,S_IRWXO|S_IRWXG|S_IRWXU,1));

...

//И работаем с ней:

//----------------------------------------------------------------------------------------------------
//задать состояние в памяти
//----------------------------------------------------------------------------------------------------
void CErrorsBased::WriteState(void)
{
 if (cUniquePtr_CMMAP.Get()==NULL) return;
 if (cUniquePtr_CMMAP.Get()->IsCreated()==false) return;
 
 uint8_t *ptr=cUniquePtr_CMMAP.Get()->GetPtr();
 ...

}
//----------------------------------------------------------------------------------------------------
//считать состояние в памяти
//----------------------------------------------------------------------------------------------------
void CErrorsBased::ReadState(void)
{
 if (cUniquePtr_CMMAP.Get()==NULL) return;
 if (cUniquePtr_CMMAP.Get()->IsCreated()==false) return;

 uint8_t *ptr=cUniquePtr_CMMAP.Get()->GetPtr();
 ...
}
//----------------------------------------------------------------------------------------------------
//задать состояние и записать в память
//----------------------------------------------------------------------------------------------------
void CErrorsBased::SetState(void)
{
 if (cUniquePtr_CSemaphore.Get()->IsCreated()==false) return;
 //блокируем семафор
 {
  CRAIICSemaphore cRAIICSemaphore(cUniquePtr_CSemaphore.Get());
  {
   ReadState();


   WriteState();
  }
 }
}

 4 
 : Декабря 04, 2018, 08:33:58 pm 
Автор qnx_user - Последний ответ от qnx_user
Добрый вечер, форумчане (если живые еще остались)!

Имеется вопрос, может быть глупповатый, но все же. Есть в проекте несколько разделяемых объектов памяти, для взаимодействия между процессами. Есть один писатель в каждую из них и несколько читателей, я написал несколько функций оберток вида:

Код:
void XXXX_ShmemLock()
{
assert( g_Shmem );
sem_wait( &g_Shmem->lock );
}

void XXXX_ShmemUnlock()
{
assert( g_Shmem );
sem_post( &g_Shmem->lock );
}

void XXXX_ShmemCopy( void *destination, const void *source, const size_t num )
{
XXXX_ShmemLock();
_disable();
memcpy( destination, source, num );
_enable();
XXXX_ShmemUnlock();
}

Дальнейшие операции более высокого уровня, выполняются путем вызова функций-оберток, как пример приложу:
Код:
void XXXX_ReadADC( const ADCChannel_t channel, double *voltage )
{
assert( channel < ADC_ChannelsNum );
// *voltage = g_Shmem->Vin[channel];
XXXX_ShmemCopy( (void *)voltage, (const void *)&g_Shmem->Vin[channel], sizeof(g_Shmem->Vin[channel]) );
}

void XXXX_WriteADC( const ADCChannel_t channel, const double voltage )
{
assert( channel < ADC_ChannelsNum );
// g_Shmem->Vin[channel] = voltage;
XXXX_ShmemCopy( (void *)&g_Shmem->Vin[channel], (const void *)&voltage, sizeof(voltage) );
}
P.S. Насколько рационален такой подход?

Так вот, как видно в функции XXXX_ShmemCopy, копирование данных в область и из нее, производится вызовом memcpy, обернутым в семафор и дополнительным отключением прерываний на момент копирования, чтобы обеспечить атомарность операции. Есть ли вообще смысл в такой перестраховке на однопроцессорной системе? Минус в использовании _disable()/_enable() при больших объемах копирования (которых скорее всего не будет), на момент выполнения операции, стопорится работа всей системы, или если вызовов XXXX_ShmemCopy будет много (а их скорее всего будет много), то рискуем то и делать что бесконечно выключать/включать прерывания. Так же есть ли необходимость защиты простых операций вида "Область->переменная = что-то записать", понятное дело не делая справа от "=" сложных операций, будет ли такая операция выполнена атомарно?

 5 
 : Ноября 09, 2018, 01:50:10 pm 
Автор Hed - Последний ответ от dmi
Регистрация новых пользователей восстановлена.

 6 
 : Ноября 08, 2018, 03:21:03 pm 
Автор Hed - Последний ответ от GrayCat
На соседнем форуме краем глаза увидел жалобу, что на QOR сейчас невозможно зарегистрироваться новичку. Это тоже вносит свой "минус" в посещаемость.

 7 
 : Ноября 06, 2018, 12:10:32 pm 
Автор Hed - Последний ответ от Hed
Привет всем!

В связи с тем, что на форуме все реже создаются новые посты (и это уже - тенденция  Cry), меня начинают одолевать опасения по поводу продолжения жизни форума. Лично для меня (и, скорее всего, для большинства участников форума) такие мысли - печальны.

Уважаемый(е) владелец(ьцы) форума, пожалуйста, оповестите нас (форумчан) о своих планах на счет дальнейшего существования форума. Было бы очень(!) прискорбно терять такую базу знаний.

 8 
 : Октября 21, 2018, 11:46:36 am 
Автор ia - Последний ответ от ia
Отчет о работе за 12 лет.

Написал шаблон программы-сервера.
Довел до законченного состояния.
А именно, добавил все, что надо, поправил все, что мог,
синхронизировал версии на С и С++, сопроводил примером.
И, главное, наконец-то, документировал. Да еще по ГОСТу.

Все!


P.S. Результат выложил.
Адрес прежний http://resmgr.narod.ru

 9 
 : Октября 20, 2018, 08:54:37 am 
Автор kim - Последний ответ от da-nie
Цитировать
метод должен принадлежать классу (не иметь дополнительных каких либо смещений при ссылке на метод)

Про смещения - это уже проблема компилятора, как он будет искать этот метод. Если я вставил дверь в дом, отныне ручка двери принадлежит дому точно так же, как и двери. Это уже пусть сам компилятор ищет, где там этот метод у кого лежит. И жаль, что он такого не умеет.

Цитировать
Но нет никакой возможности вызывать непосредственно этот метод без указания типа (смещения) конкретного базового класса.

Правильно. В данном случае есть неопределённость и требуется указание, чей именно метод мы вызываем.

Цитировать
Компилятор не сможет различить полную сигнатуру (а именно именную сигнатуру) к каким методам будет применен вызов (на уровне  CErrors::ChangeState - это неизвестно). Он затрудняется гарантировать точные ваши намерения и принимает очевидное решение - сгенерировать ошибку компиляции. Гарантировано он может обеспечить работу только для собственных методов принадлежащих к CErrors (в примере это метод SetError)

Но опять-таки, это проблема компилятора. Во время выполнения он умеет работать с таблицами виртуальных функций, то есть, ничто ему не мешает так же выяснять и куда что перенаправляется.

Цитировать
И наличие конструктора - тут не причем.

Нет-нет, тут другой вопрос был. Итак, у нас есть два модуля.
В первом в *.h объявлен класс CErrors и в *.cpp написано так:

//глобальная переменная
char name[]="123";
//конструктор
CErrors::CErrors(void)
{
 printf("%s\r\n",name);
}

Во втором в *.h объявлен класс CMain и в *.cpp написано так:
//глобальная переменная
CMain cMain;
//конструктор
CMain::CMain(void)
{
 printf("CMain!\r\n");
 CErrors *cErrors_Ptr=new CErrors();
 delete(cErrors_Ptr);
}

Модули разные, поэтому порядок инициализации между ними произвольный. Пусть CMain инициализируется первым. Вопрос был в том, будет к этому моменту инициализирована переменная name или нет. Если name задать как std::string, то точно гарантий нет. А вот если задать массивом, то получается, что да.

 10 
 : Октября 20, 2018, 03:31:59 am 
Автор kim - Последний ответ от lastcross
Цитировать
Тут проблема веселее, как мне кажется. Вообще, обычно принято делать поведение системы предсказуемым и ожидаемым.
А давайте посмотрим, что может значить запись :
Код:
typedef (CErrors::*set_function_ptr)(uint32_t,bool);
- это синоним set_function_ptr на указатель функции с сигнатурой (uint32_t,bool). При этом мы явно говорим, что метод должен принадлежать классу (не иметь дополнительных каких либо смещений при ссылке на метод). Вот ваш же пример - в нем добавлен не виртуальный метод doSome() в базовые классы. В мэйне вызывается конкретные методы объекта cErrors. Но нет никакой возможности вызывать непосредственно этот метод без указания типа (смещения) конкретного базового класса. Да, если методы не пересекаются по имени/сигнатуре - это очевидная ошибка компиляции отловить не получится. Но это только потому что мы явно вызываем методы и компилятор точно может определить наши намерения. В вашем случае - вы переводите все в рантайм. Компилятор не сможет различить полную сигнатуру (а именно именную сигнатуру) к каким методам будет применен вызов (на уровне  CErrors::ChangeState - это неизвестно). Он затрудняется гарантировать точные ваши намерения и принимает очевидное решение - сгенерировать ошибку компиляции. Гарантировано он может обеспечить работу только для собственных методов принадлежащих к CErrors (в примере это метод SetError)


Цитировать
Тем, что для объектов вызывается конструктор, а переменные просто инициализируются из секций исполняемого файла.
То есть,
char name[]="123"; - инициализируется из секции .data
CErrors cErrors; - инициализируется вызовом конструктора.

Меня интересовал вопрос, инициализируются ли классы строго после все простых типов. Судя по тому, что написано, да.
Нет, вы не совсем все верно поняли. В описании разделены - константная статическая инициализация и .. другие типы статической инициализации. И в вашем случае порядок инициализации будет в порядке их перечисления. "123" будет лежать где-то в .data как некий литерал, но сам name будет инициализироваться в любом случае в процессе выполнения и раньше  чем cErrors. И наличие конструктора - тут не причем.

Страниц: [1] 2 3 ... 10