Синхронизация потоков - PullRequest
2 голосов
/ 16 мая 2011

У меня есть один поток, который блокирует мьютекс, записывает значение в переменную, разблокирует мьютекс. Я делаю распечатку здесь, и значение было изменено. Я установил его на 1.

Когда я читаю значение переменных в другом потоке, используя блокировку, разблокирую мьютекс и считываю значение, я получаю старое значение 0.

Почему это происходит. Я блокирую и разблокирую один и тот же мьютекс правильно.

Как мне синхронизировать потоки?

EDIT:

Я объявляю мьютексы и переменные здесь

static pthread_mutex_t movementIdMutex = PTHREAD_MUTEX_INITIALIZER;
static int nav_movementId = 0;

static pthread_mutex_t newMovementMutex = PTHREAD_MUTEX_INITIALIZER;
static int nav_newMovement = 0;

Я установил здесь переменные

void nav_setMovementIdentifier(int id)
{
printf("Received movement id:%d from connectivity\n", id);

int result; /* Use the result for testing */

result = pthread_mutex_lock(&movementIdMutex);
nav_movementId = id;
printf("nav_movementId is %d\n", nav_movementId);
result = pthread_mutex_unlock(&movementIdMutex);

result = pthread_mutex_lock(&newMovementMutex);
nav_newMovement = 1;
printf("nav_newMovement is %d in the setId function\n", nav_newMovement);
result = pthread_mutex_unlock(&newMovementMutex);
printf("\n");
}

и читайте их здесь

void *startConnectivityListener(void *ptr)     {

/* Declare safety variables because segments cant be locked/unlocked 
*  using mutexes if they are checking in statement such as if and while.
*/
int newMoveCheck = 0;
int startIndoorCheck = 0;
int startOutdoorCheck = 0;

int listening = 1;

while(listening == 1)
{
    int result; /* Use for testing */

    /* check if a new movement command waits */
    result = pthread_mutex_lock(&newMovementMutex);
    newMoveCheck = nav_newMovement;
    printf("nav new movement in thread is :%d\n", nav_newMovement);
    printf("newMoveCheck in mutex lock is:%d\n", newMoveCheck);
    result = pthread_mutex_unlock(&newMovementMutex);

    result = pthread_mutex_lock(&movementIdMutex);
    printf("nav_movementId in thread is %d\n", nav_movementId);
    result = pthread_mutex_unlock(&movementIdMutex);

    printf("newMoveCheck is %d\n", newMoveCheck);
    sleep(1);

    if(newMoveCheck == 1)

Я получаю правильные распечатки в установочных функциях операторов printf, он устанавливает значения в id, который передается, и в 1.

Когда я пытаюсь распечатать его там, где я их читаю, оба по-прежнему показывают 0, то есть то, к чему они были установлены при инициализации.

Ответы [ 4 ]

1 голос
/ 18 мая 2011

Попробуйте добавить спецификатор volatile к переменным nav_movementId и nav_newMovement.

0 голосов
/ 16 мая 2011

Эти статические мьютексы и переменные находятся в том же исходном файле, что и код ниже, или они находятся в заголовке?Если они находятся в заголовке и эти две функции находятся в отдельных файлах, то у каждой есть своя собственная копия мьютекса и переменной.Вам нужно сделать их extern вместо static.

Еще одна вещь: функция «слушателя» фактически не ожидает установки переменных другой функцией - мьютекс только гарантирует, что онине активно пишется.Поэтому я не удивлюсь, если в первый раз, когда вы прочитаете nav_newMovement в слушателе, он по-прежнему равен 0. Здесь может помочь немного больше объяснения того, как вы ожидаете, что система будет работать.

0 голосов
/ 16 мая 2011

Порядок выполнения потоков не определен, то есть если вы только что запустили поток, это не значит, что порядок выполнения потоков будет в том порядке, в котором вы их запустили. Чтобы синхронизировать потоки, необходимо создать «барьеры», то есть точку в коде, где один поток не может продолжаться, пока другой поток не достигнет определенной точки. Обычно это делается с семафорами, хотя вы можете сделать это с мьютексами и условными переменными.

Концепция заключается в том, что если у вас было два потока и два семафора, вы можете заставить один поток блокироваться, пока другой поток работает. Затем, когда первый поток завершает работу, он разблокирует второй поток, а второй поток блокирует первый поток. Это может постоянно повторять, где один поток блокируется, в то время как другой поток работает, и наоборот. Таким образом, шаги будут:

  1. Поток # 1 инициализирует семафор # 1 как заблокированный, а семафор # 2 как разблокированный
  2. Поток № 1 запускает поток № 2, который затем блокирует семафор # 2 и продолжает работу
  3. Тем временем поток № 1 пытается заблокировать уже заблокированный семафор # 1, поэтому он блокируется, пока работает поток № 2
  4. Нить # 2 завершена и разблокирует семафор # 1 ... Нить # 1 теперь продолжается на
  5. Поток # 2 пытается заблокировать семафор # 2, но он заблокирован, поэтому он должен дождаться окончания работы потока # 1
  6. Тема # 1 завершает работу и разблокирует семафор # 2 ... Тема # 2 теперь продолжается
  7. Поток № 1 пытается заблокировать семафор # 1, но он заблокирован, поэтому он должен дождаться окончания работы потока № 2
  8. Продолжайте повторять, пока не достигнете какого-либо состояния отделки ...

Таким образом, в основном поток № 1 разблокирует поток № 2, и наоборот. Поток № 1 не разблокирует себя, а затем блокирует поток № 2 или какой-либо другой вариант, когда один поток должен одновременно блокировать и разблокировать семафор для себя и другого потока. Таким образом, вы не получите точку «пересечения», где ни один из потоков не заблокирован, и оба они работают свободно, или, что еще хуже, условие взаимоблокировки, когда оба потока ждут, пока другой поток разблокирует себя.

Используя семафоры, вы можете эффективно создавать «барьеры» в вашем приложении, которые позволят достичь определенного уровня детерминированности в работе потоков, и создавать потоки, которые синхронизируются друг с другом. Вы сможете определенно сказать, что поток не может продолжаться после определенной точки, пока другой поток не достигнет определенной точки ... следовательно, ваши точки синхронизации создаются с использованием внутренней природы семафора.

0 голосов
/ 16 мая 2011

Эти объявления:

static int nav_movementId = 0;
static int nav_newMovement = 0;

создают совершенно новые и разные переменные - поэтому вы не видите изменений в глобальной переменной.Сделайте объявление таким образом, чтобы функция, которая обновляет переменные, действовала на глобальные экземпляры:

extern int nav_movementId;
extern int nav_newMovement;

Аналогично, мьютексы должны быть одинаковыми экземплярами - они должны быть глобальными или вам нужнополучить их адреса совместно для модулей.

В одном модуле:

pthread_mutex_t movementIdMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t newMovementMutex = PTHREAD_MUTEX_INITIALIZER;

В заголовке (или другом модуле):

extern pthread_mutex_t movementIdMutex;
extern pthread_mutex_t newMovementMutex;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...