是的,只要任何线程使用互斥量时它仍然在作用域范围内,它就不必是全局变量。不幸的是,你确实必须告诉第二个线程互斥量在哪里,这是无法避免的。
而传递它与传递任何其他变量并没有什么区别。因此,只需在第一个线程中定义并初始化它,然后在创建第二个线程时将其地址作为线程参数传递即可。
第二个线程可以使用该地址来访问互斥锁。
就你想把函数既当做线程又当做普通函数使用的评论而言,由于复杂性,我会避免这样做。
但是你可以将大部分工作放入普通函数中,然后使线程函数成为其简单的包装器。你甚至可以传递一个互斥指针,如果有效,则可以使用它,如果为空则不使用。
有关详细信息,请参见以下完整程序。首先是一些支持内容,需要的头文件和日志函数:
#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");
}
最后是主要函数。它先在不加互斥锁的情况下调用work函数,然后创建一个互斥锁用于与另一个线程共享:
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 | | |
请特别注意没有互斥锁的直接调用与使用互斥锁的调用之间的区别。
mtx
,但在函数或其他线程中,要么传递NULL
,要么传递&mtx
。在这些地方,你需要检查是否为NULL,并且如果不是NULL,则解引用指针。 - paxdiablo