首页 > 解决方案 > 关于 pthread_mutex_lock() 函数的使用,哪一项是正确的?

问题描述

我正在学习如何通过多线程使用全局变量,但我现在有一个问题:关于pthread_mutex_lock()pthread_mutex_unlock().

function1 或 function2 中的用法正确吗?如果两者都不是,如何正确使用?

我当时只是修改了数组中的一个元素。比如改变后thread1AllSensorInfoArray[2][66].sensorType改变thread1AllSensorInfoArray[2][67].sensorType现在thread2可以改变AllSensorInfoArray[2][66].sensorType。也就是说,不允许多个线程同时修改AllSensorInfoArray[2][66].sensorType

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

pthread_mutex_t AllSensorMutex;

void *function1(void *arg)
{


    int t = 0, i = 0;
    /*
        some codes
    */
    pthread_mutex_lock(&AllSensorMutex);
    for (t = 0; t < 100; t++)
    {
        AllSensorInfoArray[i][t].sensorType = allData[2+t];
    }
    pthread_mutex_unlock(&AllSensorMutex);
    /*
        some codes
    */
}

void *function2(void *arg)
{

    /*
        some codes
    */
    int t = 0, i = 0;
    for (t = 0; t < 100; t++)
    {
        pthread_mutex_lock(&AllSensorMutex);
        AllSensorInfoArray[i][t].sensorType = allData[2+t];
        pthread_mutex_unlock(&AllSensorMutex);
    }
    /*
        some codes
    */
}

int main(void)
{
    while(pthread_mutex_init(&AllSensorMutex, NULL))
    {
        printf("(%s) write mutex init error!\n", __FUNCTION__);
        sleep(1);
    }

    pthread_t thread1;
    pthread_t thread2;
    int ret = pthread_create(&thread1, NULL, function1, NULL);
    if (ret != 0)
    {
        printf("(%s) failed to create a pthread, return error code : %d.\n", __FUNCTION__, ret);
        exit(-1);
    }

    ret = pthread_create(&thread2, NULL, function2, NULL);
    if (ret != 0)
    {
        printf("(%s) failed to create a pthread, return error code : %d.\n", __FUNCTION__, ret);
        exit(-1);
    }
    while (1)
    {
        sleep(1);
    }
}

标签: clinux

解决方案


Correct is usage in function1 or function2?

Both are equally correct, and will work. The first one is "better" for this particular case.

The first one, which takes the mutex for the duration of the loop is more efficient, because there is less overhead (of locking and unlocking the mutex). It is best suited for things like copying data.

The second one, which takes the mutex for the duration of accessing each element, is better suited when the modification is more complicated and may take some time (relatively speaking), and you only need to access that one element. However, then you should only take the mutex for the modification itself, and not for the entire computation (or, say, sensor reading):

for (i = 0; i < sensor_count; i++) {
    value = read_sensor(i);

    pthread_mutex_lock(&mutex);
    sensor_reading[i] = value;
    pthread_mutex_unlock(&mutex);
}

instead of pthread_mutex_lock(&mutex); sensor_reading[i] = read_sensor(i); pthread_mutex_unlock(&mutex);, because this latter would just hold the mutex while reading the sensor, blocking other threads' access to the array for the duration of the read_sensor(i) call for no sensible reason.

Simple assignment or arithmetic on the array element is not 'slow', and therefore the first function is the recommended pattern here.

In general, the pattern

for (i = 0; i < N; i++) {
    pthread_mutex_lock(&mutex);

    /* Do something */

    pthread_mutex_unlock(&mutex);
}

only releases the mutex for a short duration, and depending on the pthreads implementation, it may not be long enough for any other thread to grab the mutex, even if they were already blocking/waiting on the mutex (in a pthread_mutex_lock(&mutex) call). It is not wrong or an error, though, it just works the same as

pthread_mutex_lock(&mutex);
for (i = 0; i < N; i++) {

    /* Do something */

}
pthread_mutex_unlock(&mutex);

and is less efficient than this latter form, because the former does (N-1) extra pthread_mutex_lock() and pthread_mutex_unlock() calls, with no guarantees of any benefits of doing so.


推荐阅读