質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Q&A

解決済

3回答

10504閲覧

CreateMutexAの正しい使い方について

IchigoTaruto

総合スコア159

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

0グッド

0クリップ

投稿2016/09/23 04:37

編集2016/09/23 11:28

###環境
Windows 10 Home
Microsoft Visual C++ 2010 Express

###発生している問題・エラーメッセージ
同じログオンセッション内で Global\ プリフィクスのミューテックスを複数作成できるのに、異なるログオンセッションで複数作成しようとすると失敗してしまいます。(2つ目のCreateMutexAがNULLを返します)

###試したこと
ミューテックスによるプロセス間の排他制御を実現するため(方法を確認するため)、
以下のソースファイル Mutex.c を作成し、cl Mutex.c でビルドした Mutex.exe でテストを行いました。

C

1#include <stdio.h> 2#include <conio.h> 3#include <stdlib.h> 4#include <windows.h> 5 6int main(int argc, char **argv) 7{ 8 char *name; 9 HANDLE hdl; 10 int ret; 11 12 if(argc != 2) 13 return; 14 15 name = argv[1]; 16 printf("name == '%s'\n", name); 17 18 hdl = CreateMutexA(NULL, FALSE, name); 19 printf("hdl == %d\n", (int)hdl); 20 21 if(hdl == NULL) 22 return; 23 24 printf("LOCKING...\n"); 25 ret = WaitForSingleObject((HANDLE)hdl, INFINITE); 26 27 if(ret != WAIT_OBJECT_0) 28 return; // fatal 29 30 printf("LOCKED\n"); 31 32 _getch(); 33 34 ReleaseMutex(hdl); 35 CloseHandle(hdl); 36 printf("RELEASE & CLOSED\n"); 37}

2つコンソール(cmd.exe)を開き、それぞれで Mutex Global\aaa を実行したところ、以下のとおり期待通り動きました。

  1. 先に起動した方が LOCKED まで表示され、後に起動した方が LOCKING... まで表示される。
  2. 先に起動した方のコンソールで何かキーを押す。
  3. 先に起動した方が RELEASE & CLOSED を表示して終了し、後に起動した方が LOCKED まで表示される。
  4. 後に起動した方のコンソールで何かキーを押す。
  5. 後に起動した方が RELEASE & CLOSED を表示して終了する。

ですが、2ユーザーでログオンし(それぞれt,rとします)それぞれのログオンセッションで Mutex Global\aaa を実行すると以下のようになってしまいます。

  1. tユーザーのデスクトップ画面を表示し、
  2. コンソール(cmd.exe)を開き、Mutex Global\aaa を実行する。
  3. LOCKED まで表示される。
  4. ユーザーの切り替えを行いrユーザーのデスクトップ画面を表示する。
  5. コンソール(cmd.exe)を開き、Mutex Global\aaa を実行する。
  6. hdl == 0 が表示され終了してしまう。

6 において LOCKING... まで進むことを期待していたのですが、CreateMutexA がミューテックスハンドルを返さず NULL を返してきます。
CreateMutexA の使い方(引数の指定)に間違いがあるのではないかと考えています。
CreateMutexA の正しい使い方、あるいは↑のソース上の間違いをご指摘願います。

###C#の場合はうまくいった
なお、C#でも同様の問題が発生しましたが、以下URLのコードを試したところ解決しました。
http://qiita.com/hanishi@github/items/f2597dc4a351bc1f9795
なので、このコード中の

C#

1var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow); 2var securitySettings = new MutexSecurity(); 3securitySettings.AddAccessRule(allowEveryoneRule); 4mutex.SetAccessControl(securitySettings);

と同じことをやれば良いのではないかと思うのですが、Cでのやり方が見えていない状態です。


そもそも何故異なるログオンセッションで同じ名前のミューテックスを生成出来ないのでしょうか...
その理由もお教えいただけると幸いです。
よろしくお願いします。

解決しました

ご回答いただいた内容を元に以下の通り修正したところ、うまくいきました。
ありがとうございます。

C

1#pragma comment(lib, "advapi32.lib") 2 3#include <stdio.h> 4#include <conio.h> 5#include <stdlib.h> 6#include <windows.h> 7#include <winbase.h> 8 9int main(int argc, char **argv) 10{ 11 char *name; 12 HANDLE hdl; 13 int ret; 14 15 if(argc != 2) 16 return; 17 18 name = argv[1]; 19 printf("name == '%s'\n", name); 20 21 { 22 SECURITY_DESCRIPTOR sd; 23 SECURITY_ATTRIBUTES secAttribute; 24 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); 25 SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE); 26 secAttribute.nLength = sizeof(secAttribute); 27 secAttribute.lpSecurityDescriptor = &sd; 28 secAttribute.bInheritHandle = TRUE; 29 hdl = CreateMutexA(&secAttribute, FALSE, name); 30 } 31 32 printf("hdl == %d\n", (int)hdl); 33 34 if(hdl == NULL) 35 return; 36 37// _getch(); 38 39 printf("LOCKING...\n"); 40 ret = WaitForSingleObject((HANDLE)hdl, INFINITE); 41 42 if(ret != WAIT_OBJECT_0) 43 return; // fatal 44 45 printf("LOCKED\n"); 46 47 _getch(); 48 49 ReleaseMutex(hdl); 50 CloseHandle(hdl); 51 printf("RELEASE & CLOSED\n"); 52}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

少々古いですが、こういう記事がありました。
http://d.hatena.ne.jp/cjohn/20081204/1228397004
要は別ユーザーで実行するとエラーになるとのことです。
CreateMutexの第一引数を適切に設定するとよいようです。
記事を参考に実装してみてください。

投稿2016/09/23 04:51

ttyp03

総合スコア16998

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

IchigoTaruto

2016/09/23 11:23

URLの記事のとおりやったところうまくいきました。 ありがとうございます。
guest

0

他の方の回答にもあるように、セキュリティー権限の問題でしょうね。
Global\ 名前空間にあるからと言って、誰でも(どのような権限でも)アクセス可能とは限りません。
(特定ユーザーしか読み書きできないアクセス権設定をしているファイルを、別ユーザーから読み書きしようとしたら、権限がないため処理に失敗するのと同じですね)

MSDNのヘルプにもあるように、CreateMutex() が失敗した場合(NULLが返された場合)は、GetLastError()を使用して詳細なエラー情報を確認しましょう。

おそらく、アクセス権限がない旨のエラー値が返されてるはずです。

投稿2016/09/23 11:34

KenjiToriumi

総合スコア344

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

IchigoTaruto

2016/09/23 11:42

なるほど、ユーザーtが Global\aaa を作成したら、デフォルトではtしかアクセス権がなくて、ユーザーrが開こうとしても権限が無くて開けないと、、 合点がいきました。 ありがとうございます。
guest

0

こんにちは。

今回のケースは恐らく「別のユーザで実行」と同等な処理を行っていることになると思います。
ここを見ると、「別のユーザで実行」するとNULLが返ってくるそうです。セキュリティ記述子を省略しなければ大丈夫なようです。

投稿2016/09/23 04:52

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

IchigoTaruto

2016/09/23 11:23

URLの記事のとおりやったところうまくいきました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問