没有全局互斥锁的 pThread 互斥锁

Fan*_*Fox 3 c++ mutex pthreads thread-safety

我在 pThread 库中看到的关于互斥锁的所有教程都使用了全局互斥锁:

看:

https://computing.llnl.gov/tutorials/pthreads/#Mutexes

http://www.drdobbs.com/cpp/184401518?pgno=3(用于 boost::thread 但上下文相同)

我想要做的是使用互斥锁,其中主文件的 Global 超出了需要锁定变量的函数的范围。这是一个例子:

主程序

int main() {
    some initilisation code.
    tree * tree1;
    *Start thread to visualise tree* (see code below)

    Mutex Lock:
         delete tree1;
         tree1 = newTree();
    Mutex Unlock
Run Code Online (Sandbox Code Playgroud)

可视化工具.cpp

visualise(Tree *) {
    Forever:
    Mutex Lock:
         Check for tree change.
         Update tree image.
         Display tree image.
    Mutex Unlock
Run Code Online (Sandbox Code Playgroud)

我想知道这是否可能:

  1. 没有全局范围互斥锁。
  2. 如果可能,不将互斥体传递给可视化函数。

我知道这可能不合理,如果不是,我将如何使用 extern 将全局范围变量获取到 visualiser.cpp?

另外,如果我需要将互斥锁传递给函数,我将如何去做?

pax*_*blo 5

是的,只要互斥锁在任何线程使用它时保持在范围内,它就不必是全局的。你必须告诉第二个线程在互斥锁,还有周围没有办法很遗憾。

传递它与传递任何其他变量没有什么不同。

因此,只需在第一个线程中定义并初始化它,然后在创建第二个线程时,将其地址作为线程参数传递。

然后第二个线程可以使用该地址访问互斥锁。


就您希望函数既可用作线程又可用作普通函数的评论而言,由于复杂性,我会避免这样做。

可以做的是将大部分工作放入一个普通函数中,然后让线程函数成为一个简单的包装器。您甚至可以传入一个互斥体指针,如果有效则可以使用该指针,如果为 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');
}
Run Code Online (Sandbox Code Playgroud)

接下来,将完成工作的函数。这是以一种可以从任何线程调用它的方式构建的,如果您希望它使用互斥指针,可以传递一个互斥指针:

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");
}
Run Code Online (Sandbox Code Playgroud)

然后是一个实际的线程函数,它实际上是上面工作函数的一个薄包装。请注意,它通过特定于线程的参数接收互斥锁并将其传递给工作函数:

static void *mythread (void *ptr) {
    mylog (1, "starting");

    mylog (1, "call fn with mutex");
    myfunction (ptr);
    mylog (1, "and back");

    mylog (1, "stopping");
}
Run Code Online (Sandbox Code Playgroud)

最后,主要功能。这首先调用没有互斥锁的工作函数,然后创建一个互斥锁用于与其他线程共享:

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;
}
Run Code Online (Sandbox Code Playgroud)

您可以在输出中看到代码本身是如何排序的:

         |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             |                    |                    |
Run Code Online (Sandbox Code Playgroud)

请特别注意与使用互斥锁的调用相比,不使用互斥锁的直接调用的作用方式。