8

POSIX標準では、名前付き共有メモリブロックにミューテックスと条件変数を含めることができますか?

ミューテックスと条件変数を使用して、LynuxWorks LynxOS-SEシステム(POSIX準拠)上の2つのプロセスによる名前付き共有メモリへのアクセスを同期しようとしています。

1つの共有メモリブロックが呼び出さ"/sync"れ、ミューテックスと条件変数が含まれ、もう1つは、"/data"アクセスを同期している実際のデータが含まれています。

pthread_cond_signal()両方のプロセスがまったく同じ順序mmap()で呼び出しを実行しない場合、または1つのプロセスがメモリをmmapする前にの共有メモリをmmapする場合に、エラーが発生します。"/sync"

このサンプルコードは、私が作成できる限り短いものです。

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <iostream>
#include <string>
using namespace std;

static const string shm_name_sync("/sync");
static const string shm_name_data("/data");

struct shared_memory_sync
{
  pthread_mutex_t mutex;
  pthread_cond_t condition;
};

struct shared_memory_data
{
  int a;
  int b;
};


//Create 2 shared memory objects
// - sync contains 2 shared synchronisation objects (mutex and condition)
// - data not important 
void create()
{
  // Create and map 'sync' shared memory
  int fd_sync = shm_open(shm_name_sync.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
  ftruncate(fd_sync, sizeof(shared_memory_sync));
  void* addr_sync = mmap(0, sizeof(shared_memory_sync), PROT_READ|PROT_WRITE, MAP_SHARED, fd_sync, 0);
  shared_memory_sync* p_sync = static_cast<shared_memory_sync*> (addr_sync);

    // init the cond and mutex
  pthread_condattr_t cond_attr;
    pthread_condattr_init(&cond_attr);
    pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
    pthread_cond_init(&(p_sync->condition), &cond_attr);
    pthread_condattr_destroy(&cond_attr);

    pthread_mutexattr_t m_attr;
    pthread_mutexattr_init(&m_attr);
    pthread_mutexattr_setpshared(&m_attr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(&(p_sync->mutex), &m_attr);
    pthread_mutexattr_destroy(&m_attr);

  // Create the 'data' shared memory   
  int fd_data = shm_open(shm_name_data.c_str(), O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
  ftruncate(fd_data, sizeof(shared_memory_data));
  
  void* addr_data = mmap(0, sizeof(shared_memory_data), PROT_READ|PROT_WRITE, MAP_SHARED, fd_data, 0);
  shared_memory_data* p_data = static_cast<shared_memory_data*> (addr_data);

  // Run the second process while it sleeps here.
  sleep(10);

  int res = pthread_cond_signal(&(p_sync->condition));
  assert(res==0);  // <--- !!!THIS ASSERT WILL FAIL ON LYNXOS!!!

  munmap(addr_sync, sizeof(shared_memory_sync));
  shm_unlink(shm_name_sync.c_str());
  munmap(addr_data, sizeof(shared_memory_data));
  shm_unlink(shm_name_data.c_str());
}

//Open the same 2 shared memory objects but in reverse order
// - data
// - sync 
void open()
{
  sleep(2);
  int fd_data = shm_open(shm_name_data.c_str(), O_RDWR, S_IRUSR|S_IWUSR);
  void* addr_data = mmap(0, sizeof(shared_memory_data), PROT_READ|PROT_WRITE, MAP_SHARED, fd_data, 0);
  shared_memory_data* p_data = static_cast<shared_memory_data*> (addr_data);

  int fd_sync = shm_open(shm_name_sync.c_str(), O_RDWR, S_IRUSR|S_IWUSR);
  void* addr_sync = mmap(0, sizeof(shared_memory_sync), PROT_READ|PROT_WRITE, MAP_SHARED, fd_sync, 0);
  shared_memory_sync* p_sync = static_cast<shared_memory_sync*> (addr_sync);

  // Wait on the condvar
  pthread_mutex_lock(&(p_sync->mutex));
  pthread_cond_wait(&(p_sync->condition), &(p_sync->mutex));
  pthread_mutex_unlock(&(p_sync->mutex));
  
  munmap(addr_sync, sizeof(shared_memory_sync));
  munmap(addr_data, sizeof(shared_memory_data));
}

int main(int argc, char** argv) 
{
  if(argc>1)
  {
    open(); 
  }
  else
  {
    create();
  }

    return (0);
}

argsなしでこのプログラムを実行し、次にargsを使用して別のコピーを実行すると、最初のプログラムはアサートチェックで失敗しpthread_cond_signal()ます。ただし、open()関数mmap()の順序を"/sync「メモリ」に変更する"/data"と、すべて正常に機能します。

これは私にはLynxOSの大きなバグのように思えますが、LynuxWorksは、このように名前付き共有メモリ内でミューテックスと条件変数を使用することはPOSIX標準でカバーされていないため、関心がないと主張しています。

このコードが実際にPOSIXに違反しているかどうかを誰かが判断できますか?
または、POSIXに準拠しているという説得力のあるドキュメントを持っている人はいますか?

編集PTHREAD_PROCESS_SHARED:それがPOSIXであり、LynxOSでサポートされていることはわかっています。競合の領域は、ミューテックスとセマフォを名前付き共有メモリ内で使用できるかどうか(これまでのように)、またはPOSIXで、1つのプロセスが共有メモリを作成してmmapし、2番目のプロセスをフォークする場合にのみ使用できるかどうかです。

4

3 に答える 3

5

このpthread_mutexattr_setpshared関数を使用すると、共有メモリ内の pthread ミューテックスに、そのメモリにアクセスできる任意のスレッド (異なるプロセス内のスレッドであっても) からアクセスできます。このリンクによると、 pthread_mutex_setpsharedPOSIX P1003.1c に準拠しています。(条件変数についても同じことが言えます。 を参照してくださいpthread_condattr_setpshared。)

関連する質問: Linux での pthread 条件変数、奇妙な動作

于 2010-05-06T17:35:46.933 に答える
4

PTHREAD_PROCESS_SHARED を OS レベルで実装するのがいかに難しいかは簡単にわかります (たとえば、MacOS はそうではありませんが、rwlocks のようです)。しかし、標準を読んだだけでは、あなたには理由があるようです。

完全を期すために、 sysconf(_SC_THREAD_PROCESS_SHARED)および *_setpshared() 関数呼び出しの戻り値をアサートすることをお勧めします。別の「驚き」が待っている可能性があります (ただし、SHARED が既にチェックされていることをコメントから確認できます)。実際にサポートされています)。

@JesperE: HP ドキュメントではなく、OpenGroup の API ドキュメントを参照することをお勧めします。

于 2010-05-11T08:30:02.607 に答える
1

pthread_cond_t(pshared なしで) にいくつかのポインターがある可能性があるため、両方のスレッド/プロセスで同じアドレスに配置する必要があります。同じ順序の mmap を使用すると、両方のプロセスで同じアドレスを取得できます。

glibc では、cond_t のポインターはスレッドのスレッド記述子であり、mutex/cond を所有していました。

最初のパラメーターが NULL でないアドレスを mmap に制御できます。

于 2010-05-16T06:23:11.983 に答える