Reputation: 33864
All of the tutorials i have seen for Mutex locking with the pThread library have used a Global Mutex Lock:
See:
https://computing.llnl.gov/tutorials/pthreads/#Mutexes
http://www.drdobbs.com/cpp/184401518?pgno=3 (for boost::thread but same context)
What I would like to do is to use Mutex locking where the Global of the main file is out of scope for the function needing to lock the variable. here is an example:
Main.cpp
int main() {
some initilisation code.
tree * tree1;
*Start thread to visualise tree* (see code below)
Mutex Lock:
delete tree1;
tree1 = newTree();
Mutex Unlock
visualiser.cpp
visualise(Tree *) {
Forever:
Mutex Lock:
Check for tree change.
Update tree image.
Display tree image.
Mutex Unlock
I would like to know if this is possible:
I understand that this may not be plausable, if not how would i get the global scope variable to the visualiser.cpp, using an extern?
Also if i need to pass the mutex to the function how would i go about doing that?
Upvotes: 3
Views: 8073
Reputation: 881423
Yes, provided the mutex stays in scope while any thread is using it, it doesn't have to be global. You do have to tell the second thread where the mutex is, there's no way around that unfortunately.
And passing it is no different from passing any other variable.
So, simply define it and initialise it in your first thread then, when creating your second thread, pass its address as the thread argument.
The second thread can then use that address to access the mutex.
In terms of your comment where you want a function to be both usable as a thread and simply a normal function, I'd steer clear of that just because of the complexity.
What you can do is to put most of the work into a normal function and then make the thread function a simple wrapper around that. You can even pass in a mutex pointer which can be used if valid, or not used if NULL.
See the following complete program for details. First, some support stuff, needed headers and a logging function:
#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');
}
Next, the function which will do the work. This is built in such a way that it can be called from any thread, and can be passed a mutex pointer if you want it to use one:
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");
}
Then an actual thread function, which is really a thin wrapper around the work function above. Note that it receives the mutex via the thread-specific parameter and passes that on to the work function:
static void *mythread (void *ptr) {
mylog (1, "starting");
mylog (1, "call fn with mutex");
myfunction (ptr);
mylog (1, "and back");
mylog (1, "stopping");
}
And finally, the main function. This first calls the work function without a mutex, then creates a mutex for sharing with the other thread:
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;
}
You can see in the output how the code sequences itself:
|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 | | |
Note especially how the direct call with no mutex acts, as compared to the call with the mutex.
Upvotes: 5
Reputation: 10357
Its actually not thread-safe to pass in and use a different mutex instantiation per thread, as this will not synchronize multiple thread accesses to an object common to all the threads in question.
Generally you should have a mutex per object/data structure instance, not one per thread. That being said, it would make more sense for the object that needs to be synchronized to have a mutex attribute, and for it to be managed internally in the methods that need to be synchronized.
Regarding the mention of Global mutex, and considering my previous paragraph, the mutex should effectively be global to the context of the object being synchronized and the threads involved. That is, the same mutex should be common and available to all of those entities. This can be achieved without making it a global variable, though as mentioned earlier.
Upvotes: 0
Reputation: 1069
The answer will become apparent once you convert your code from pseudo code to concrete code.
For example:
Your visualizer thread has to "Check for tree change."
How do you do this? You have to have a data structure that can tell you this information. This ds will be updated by the main thread.
So you keep the mutex inside that data structure. It can be global or on heap
Upvotes: 1