简体   繁体   English

C:线程同步使用pthreads,锁定和解锁互斥锁

[英]C: Thread synchronization using pthreads, locking and unlocking mutex

I'm working on a larger project including two threads, where one database is shared between them.我正在做一个更大的项目,包括两个线程,其中一个数据库在它们之间共享。 One threads job is to just count down every active elements timer, when the timer for that element is zero it should set it inactive and zero it out.一个线程的工作是倒计时每个活动元素计时器,当该元素的计时器为零时,它应该将其设置为非活动并将其归零。

The main thread is just manipulating the active element's other variables in some way.主线程只是以某种方式操作活动元素的其他变量。

I am not sure how to synchronize these threads, especially as the timer thread cleans up the database element when the timer reaches zero.我不知道如何同步这些线程,特别是当计时器达到零时计时器线程清理数据库元素时。 Right now I believe that the time between unlocking and locking the mutex in the while(1) loop in main() may be too fast?现在我相信在main()while(1)循环中解锁和锁定mutex之间的时间可能太快了?

If the timer thread is waiting for the mutex to unlock at pthread_mutex_lock() ;如果计时器线程pthread_mutex_lock()等待mutex解锁; and it unlocks in main() , do we know that the timer thread will be the next one to lock the mutex or might the main() be so fast that it locks it again as there is no task between pthread_mutex_unlock() and pthread_mutex_lock() ?并且它在main()中解锁,我们是否知道计时器线程将是下一个锁定mutex锁的线程,或者main()可能太快以至于它再次锁定它,因为pthread_mutex_unlock()pthread_mutex_lock() () 之间没有任务pthread_mutex_lock() ?

I have no experience using condition variables, may that be a good idea here?我没有使用条件变量的经验,这可能是个好主意吗?

Here is a minimal working example of my much larger project.这是我更大的项目的最小工作示例。

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <time.h>

#define NUM_COMPUTER 10

typedef struct computer
{
    unsigned int active;
    unsigned int timer;
    int x;
}computer_t;

/**
 * Function declarations
 */
void activate(computer_t* comp);
void* timerFunction(void* args);

/**
 * Global variables
 */
computer_t database[NUM_COMPUTER];
pthread_mutex_t mutex;

main() function主要() function

/**
 * Main
 */
int main(void)
{
    memset(database, 0, sizeof database);

    // Initialize some database elements
    activate(database);
    database[0].x = 5;

    activate(database + 3);
    database[3].x = 23;

    activate(database + 9);
    database[9].x = -7; 

    pthread_t timer_thread;
    pthread_create(&timer_thread, NULL, timerFunction, NULL);

    while(1)
    {
        /**
         * MAY PROBLEMS OCCUR HERE? UNLOCKING AND LOCKING ALMOST DIRECTLY
         */
         
        // ************* LOCK *************
        pthread_mutex_lock(&mutex);

        /**
         * Manipulate struct members 
         */
        for (int i = 0; i < NUM_COMPUTER; i++)
        {
            if (database[i].active)
            {
                database[i].x += 1;
            }
        }
        // ************* UNLOCK *************
        pthread_mutex_unlock(&mutex);
    }

    return 0;
}

Extra functions额外功能

void activate(computer_t* comp)
{
    comp->active = 1;
    comp->timer = 100;
}

void* timerFunction(void* args)
{
    struct timespec ts;

    // Sleep interval before checking database again
    ts.tv_sec = 1;
    ts.tv_nsec = 0;

    while(1)
    {
        // ************* LOCK *************
        pthread_mutex_lock(&mutex);

        /**
         * Go through every database index
         */
        for (int index = 0; index < NUM_COMPUTER; index++)
        {   
            if (database[index].active)
            {
                if (database[index].timer > 0)
                {
                    database[index].timer--;
                }
                else
                {
                    /**
                     * Clean up database index
                     */
                    memset(database + index, 0, sizeof database);
                }
            }
        }

        // ************* UNLOCK *************
        pthread_mutex_unlock(&mutex);

        /**
         * Sleep 1 sec before checking database again
         */
        nanosleep(&ts, NULL);
    }
}

If the timer thread is waiting for the mutex to unlock at pthread_mutex_lock() ;如果计时器线程pthread_mutex_lock()等待mutex解锁; and it unlocks in main() , do we know that the timer thread will be the next one to lock the mutex它在main()中解锁,我们是否知道计时器线程将是下一个锁定mutex锁的线程

No.不。

At least, not in general.至少,不是一般的。 This is question of thread scheduling policy, which your particular platform may or may not allow you to adjust.这是线程调度策略的问题,您的特定平台可能允许也可能不允许您调整。 The pthreads API makes no guarantees in this area. pthreads API 在这方面不做任何保证。

or might the main() be so fast that it locks it again as there is no task between pthread_mutex_unlock() and pthread_mutex_lock() ?或者可能main()太快以至于它再次锁定它,因为pthread_mutex_unlock()pthread_mutex_lock()之间没有任务?

It is not only possible, but fairly likely that this happens at least some of the time.这不仅是可能的,而且很有可能至少在某些时候会发生。

I have no experience using condition variables, may that be a good idea here?我没有使用条件变量的经验,这可能是个好主意吗?

Condition variables are an important tool to have in your belt, but I see no reason to think that they would be a particular help here.条件变量是随身携带的重要工具,但我认为没有理由认为它们在这里会有特别的帮助。

The main problem with the code you present is that both threads have to lock substantially the whole world for their own exclusive use whenever they are active.您提供的代码的主要问题是,两个线程必须在它们处于活动状态时基本上锁定整个世界以供自己独占使用。 As such, even if all the locking worked as desired, you would have no true concurrency, hence multithreading is adding complexity without conferring any actual advantages.因此,即使所有锁定都按预期工作,您也不会有真正的并发性,因此多线程会增加复杂性而不会赋予任何实际优势。

If you want to continue in that mode, then I would drop the multithreading and instead set up a POSIX timer to raise a flag at one-second intervals (or whatever interval you prefer).如果您想继续在该模式下,那么我会放弃多线程,而是设置一个POSIX 计时器以每隔一秒(或您喜欢的任何间隔)引发一个标志。 Then your single-threaded program can check that flag at the top of each loop iteration to determine whether to perform its normal work or one pass of timeout management.然后,您的单线程程序可以在每次循环迭代的顶部检查该标志,以确定是执行其正常工作还是执行一次超时管理。

If you want true concurrency then you probably need to either shrink the critical regions guarded by your mutex, or change from a single mutex protecting everything to multiple mutexes, each protecting a subset of all the things.如果您想要真正的并发,那么您可能需要缩小由互斥锁保护的关键区域,或者从保护所有内容的单个互斥锁更改为多个互斥锁,每个互斥锁保护所有事物的子集。 Perhaps you could alternatively rework things around atomic objects and operations instead of mutexes, but what I see so far does not give me much confidence in that.也许您可以替代地围绕原子对象和操作而不是互斥体进行修改,但到目前为止我所看到的并没有让我对此充满信心。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM