首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不带全局互斥锁的pThread互斥锁

不带全局互斥锁的pThread互斥锁
EN

Stack Overflow用户
提问于 2012-05-31 05:40:04
回答 3查看 7.6K关注 0票数 3

我在pThread库中看到的关于Mutex锁定的所有教程都使用了Global锁:

请参见:

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

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

我想做的是在主文件的全局超出需要锁定变量的函数的作用域时使用Mutex锁定。以下是一个例子:

Main.cpp

代码语言:javascript
复制
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

代码语言:javascript
复制
visualise(Tree *) {
    Forever:
    Mutex Lock:
         Check for tree change.
         Update tree image.
         Display tree image.
    Mutex Unlock

我想知道这是否可能:

没有全局范围互斥锁的

  1. .
  2. (如果可能的话),而不将互斥对象传递给可视化函数.

我知道这可能是不可利用的,如果不是的话,我如何使用外部程序将全局范围变量传递给visualiser.cpp呢?

另外,如果我需要把互斥传递给函数,我该怎么做呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-05-31 05:43:53

是的,如果在任何线程使用互斥锁时互斥体保持在作用域中,它就不一定是全局的。你必须告诉第二个线程互斥体在哪里,不幸的是,没有办法绕过它。

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

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

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

在您的评论中,您希望一个函数既可以作为线程使用,又可以简单地作为一个普通函数使用,我会避开它,因为它非常复杂。

您可以做的是将大部分工作放入一个普通函数中,然后使线程函数成为一个简单的包装器。您甚至可以传入一个互斥指针,如果有效,可以使用它,如果为NULL,则不能使用。

有关详细信息,请参阅以下完整的程序。首先,一些支持内容、所需的标题和日志功能:

代码语言:javascript
复制
#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');
}

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

代码语言:javascript
复制
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");
}

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

代码语言:javascript
复制
static void *mythread (void *ptr) {
    mylog (1, "starting");

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

    mylog (1, "stopping");
}

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

代码语言:javascript
复制
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;
}

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

代码语言:javascript
复制
         |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             |                    |                    |

特别要注意,与使用互斥的调用相比,没有互斥的直接调用是如何工作的。

票数 5
EN

Stack Overflow用户

发布于 2012-05-31 06:47:09

当您将代码从伪代码转换为具体代码时,答案将变得显而易见。

例如:

您的可视化线程必须“检查树的更改”。

你是怎么做到的?您必须有一个可以告诉您这些信息的数据结构。这个ds将由主线程更新。

所以你把互斥锁放在那个数据结构里。它可以是全局的,也可以是堆的。

票数 1
EN

Stack Overflow用户

发布于 2012-05-31 06:55:46

实际上,每个线程传入并使用不同的互斥实例化并不是线程安全的,因为这不会同步多个线程对所有相关线程共有的对象的访问。

通常,每个对象/数据结构实例应该有一个互斥,而不是每个线程一个。也就是说,需要同步的对象具有互斥属性,并且需要在需要同步的方法中对其进行内部管理,这将更有意义。

关于全局互斥,并考虑到我的上一段,互斥应该对同步对象的上下文和所涉及的线程有效地是全局的。也就是说,相同的互斥应该是通用的,并且对所有这些实体都是可用的。尽管如前所述,这可以在不使其成为全局变量的情况下实现。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10828001

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档