はい、スレッドがミューテックスを使用している間、ミューテックスがスコープ内にとどまる場合は、グローバルである必要はありません。ミューテックスがどこにあるかを2番目のスレッドに伝える必要がありますが、残念ながらそれを回避する方法はありません。
そして、それを渡すことは、他の変数を渡すことと同じです。
したがって、単純に定義して最初のスレッドで初期化し、2番目のスレッドを作成するときに、そのアドレスをスレッド引数として渡します。
次に、2番目のスレッドはそのアドレスを使用してミューテックスにアクセスできます。
関数をスレッドとしても単純に通常の関数としても使用できるようにしたいというコメントに関しては、複雑さのためにそれを避けたいと思います。
あなたができることは、ほとんどの作業を通常の関数に入れてから、スレッド関数をその周りの単純なラッパーにすることです。有効な場合は使用できるミューテックスポインタを渡すことも、NULLの場合は使用しないミューテックスポインタを渡すこともできます。
詳細については、次の完全なプログラムを参照してください。まず、いくつかのサポート、必要なヘッダー、およびロギング機能:
#include <pthread.h>
#include <stdio.h>
#include <time.h>
static void mylog (int indent, char *s) {
int i;
time_t now = time (NULL);
struct tm *lt = localtime (&now);
printf ("%02d:%02d:%02d ", lt->tm_hour, lt->tm_min, lt->tm_sec);
putchar ('|');
for (i = 0; i < indent; i++) printf ("%-20s|", "");
printf ("%-20s|", s);
for (i = indent + 1; i < 3; i++) printf ("%-20s|", "");
putchar ('\n');
}
次に、作業を行う関数。これは、任意のスレッドから呼び出すことができるように構築されており、ミューテックスポインターを使用する場合は、ミューテックスポインターを渡すことができます。
static void *myfunction (void *ptr) {
pthread_mutex_t *pMtx = ptr;
mylog (2, "starting");
if (pMtx != NULL) {
mylog (2, "locking mutex");
pthread_mutex_lock (pMtx);
mylog (2, "locked mutex");
}
mylog (2, "sleeping");
sleep (5);
mylog (2, "finished sleeping");
if (pMtx != NULL) {
mylog (2, "unlocking mutex");
pthread_mutex_unlock (pMtx);
}
mylog (2, "stopping");
}
次に、実際のスレッド関数。これは、実際には上記の作業関数の薄いラッパーです。スレッド固有のパラメーターを介してミューテックスを受け取り、それを作業関数に渡すことに注意してください。
static void *mythread (void *ptr) {
mylog (1, "starting");
mylog (1, "call fn with mutex");
myfunction (ptr);
mylog (1, "and back");
mylog (1, "stopping");
}
そして最後に、主な機能。これは、最初にミューテックスなしで作業関数を呼び出し、次に他のスレッドと共有するためのミューテックスを作成します。
int main (void) {
pthread_mutex_t mtx;
pthread_t tid1;
char buff[100];
printf (" |%-20s|%-20s|%-20s|\n", "main", "thread", "workfn");
printf (" |%-20s|%-20s|%-20s|\n", "====", "======", "======");
mylog (0, "starting");
mylog (0, "call fn, no mutex");
myfunction (NULL);
mylog (0, "and back");
mylog (0, "initing mutex");
pthread_mutex_init (&mtx, NULL);
mylog (0, "locking mutex");
pthread_mutex_lock (&mtx);
mylog (0, "locked mutex");
mylog (0, "starting thead");
pthread_create (&tid1, NULL, mythread, &mtx);
mylog (0, "sleeping");
sleep (5);
mylog (0, "sleep done");
mylog (0, "unlocking mutex");
pthread_mutex_unlock (&mtx);
mylog (0, "joining thread");
pthread_join (tid1, NULL);
mylog (0, "joined thread");
mylog (0, "exiting");
return 0;
}
出力で、コードがそれ自体をどのようにシーケンスするかを確認できます。
|main |thread |workfn |
|==== |====== |====== |
15:07:10 |starting | | |
15:07:10 |call fn, no mutex | | |
15:07:10 | | |starting |
15:07:10 | | |sleeping |
15:07:15 | | |finished sleeping |
15:07:15 | | |stopping |
15:07:15 |and back | | |
15:07:15 |initing mutex | | |
15:07:15 |locking mutex | | |
15:07:15 |locked mutex | | |
15:07:15 |starting thead | | |
15:07:15 |sleeping | | |
15:07:15 | |starting | |
15:07:15 | |call fn with mutex | |
15:07:15 | | |starting |
15:07:15 | | |locking mutex |
15:07:20 |sleep done | | |
15:07:20 |unlocking mutex | | |
15:07:20 |joining thread | | |
15:07:20 | | |locked mutex |
15:07:20 | | |sleeping |
15:07:25 | | |finished sleeping |
15:07:25 | | |unlocking mutex |
15:07:25 | | |stopping |
15:07:25 | |and back | |
15:07:25 | |stopping | |
15:07:25 |joined thread | | |
15:07:25 |exiting | | |
特に、ミューテックスを使用した呼び出しと比較して、ミューテックスを使用しない直接呼び出しがどのように機能するかに注意してください。