Синхронизация в многопоточности

#c #multithreading #operating-system #mutex

#c #многопоточность #операционная система #мьютекс

Вопрос:

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

Я хочу проверить правильность строк в 2D-массиве размером 9. Каждая строка должна содержать значения (от 1 до 9). Для этого я создал поток с именем «void * checkingRows (void * arg)» в основном потоке и соединил его с main. Затем поток checkingRows создает еще 9 потоков, которые проверяют правильность каждой строки.

 ````````````````````````````````````
Pthread_t id1;
pthread_mutex_t mut1;
int arr[9][9] = {  
                    {6,2,4,5,3,9,1,8,7},
                    {6,6,9,7,2,8,6,3,4},
                    {8,3,7,6,1,4,2,9,5},
                    {1,4,3,8,6,5,7,2,9},
                    {9,5,8,2,4,7,3,6,1},
                    {7,6,2,3,9,1,4,5,8},
                    {3,7,1,9,5,6,8,4,2},
                    {4,9,6,1,8,2,5,7,3},
                    {2,8,5,4,7,3,9,1,6}
                };
````````````````````````````````````
void* rowCheck(void* arg){
    int* argument = (int*) arg;
    int idx = *argument;
    int count = 0;
    for(int i = 0; i < 9; i  ){
        int temp = arr[idx][i];
        count = 0;
        for(int j = i; j < 9; j  ){
            if(arr[idx][j] == temp || arr[idx][j] <= 0 || arr[idx][j] >= 10){
                count  ; 
            }
            if(count > 1){
                pthread_mutex_lock(amp;mut1);
                count = 0;
                cout<<"ERROR at"<<arr[idx][j]<<endl;
                pthread_mutex_unlock(amp;mut1);
                break;
            }
        }
    }
    pthread_exit(NULL);
}

````````````````````````````````````
void* checkingRows(void* arg){
    int *row = new int;
    *row = 0;
    for(int i = 0; i<gridSize; i  ){
        pthread_create(amp;workerIdRow[i], NULL, amp;rowCheck, row);
        *row = *row   1;
    }
    pthread_exit(NULL);
}
`````````````````````````````````
int main(){

    pthread_mutex_init(amp;mut1, NULL);
    pthread_create(amp;id1, NULL, amp;checkingRows, NULL);
    pthread_join(id1,NULL);

    retrun 0;

}
````````````````````````````````````

ERROR at 6
ERROR at 6
 

Комментарии:

1. Использование new int и cout указывает, что это C , а не C.

2. Обратите внимание, что в pthread_create(..., amp;rowCheck, row); строке находится указатель, и вы передаете каждому потоку один и тот же указатель, независимо от того, указывает ли значение int на.

3. Вместо того чтобы использовать pthreads, я предлагаю вам взглянуть на std::thread то, что представляет собой портативная встроенная библиотека потоков…

4. У вас есть retrun в main (вместо return )

5. Какой смысл звонить pthread_join(id1,NULL) сразу после звонка pthread_create(amp;id1,NULL,amp;checkingRows,NULL) ? Почему бы вам просто не позвонить checkintRows(NULL) в этот момент?

Ответ №1:

Вы спрашиваете,

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

, и я думаю, что вы говорите об этих:

checkingRows создает еще 9 потоков, которые проверяют правильность каждой строки.

Конечно, они не могут запускаться раньше main() , по крайней мере, до main запуска, если вы не запустите их в этот период времени. Вы этого не делаете. Но я думаю, что на самом деле вам нужно только то, что они заканчивают до main того, как пройдут мимо определенной точки.

Ну, это pthread_join то, для чего нужно. Я вижу, что вы уже используете эту функцию main() для потока, который она запускает, но, возможно, вас смущает тот факт, что это не влияет на дополнительные потоки, запущенные вторым.

Это просто не работает автоматически таким образом. После запуска потоки выполняются независимо друг от друга. Если вы хотите дождаться завершения потока, вы должны присоединиться к этому конкретному потоку. В вашем случае это, вероятно, означает, что checkingRows() он должен присоединяться к каждому потоку, который он запускает, прежде чем он сам завершится.

Ответ №2:

Первый созданный поток бесполезен, потому что вы создаете его и немедленно ожидаете его окончания

Напротив, вы не ждете окончания 9 других потоков, поэтому вы завершаете работу до их окончания

Когда вы запускаете подпотоки, у вас нет синхронизации, чтобы убедиться, что у них есть время прочитать номер строки, прежде чем изменять его для следующего потока, несколько могут проверять одну и ту же строку. Для этого вы можете использовать условие (все еще используя библиотеку потоков C), или вы можете каждый раз указывать вновь созданный int с учетом индекса.

У вас утечка памяти, потому что вы не удаляете int, и фактически бесполезно выделять его в куче в вашем случае


Предложение из вашего кода, как вы можете видеть, я напрямую указываю адрес соответствующей строки каждому потоку, я удалил промежуточный поток и жду окончания 9 потоков, еще некоторые другие изменения

 #include <pthread.h>
#include <iostream>

pthread_mutex_t mut1;

int arr[9][9] = {  
                    {6,2,4,5,3,9,1,8,7},
                    {6,6,9,7,2,8,6,3,4},
                    {8,3,7,6,1,4,2,9,5},
                    {1,4,3,8,6,5,7,2,9},
                    {9,5,8,2,4,7,3,6,1},
                    {7,6,2,3,9,1,4,5,8},
                    {3,7,1,9,5,6,8,4,2},
                    {4,9,6,1,8,2,5,7,3},
                    {2,8,5,4,7,3,9,1,6}
                };

void * rowCheck(void* arg)
{
    int * row = (int *) arg;
    const char * result = "ok";

    for(int i = 0; i < 9; i  ){
      int temp = row[i];
      int count = 0;

      for(int j = i; j < 9; j  ){
        if(row[j] == temp || row[j] <= 0 || row[j] >= 10){
          count  ; 
        }
        if(count > 1){
          result = "ko";
          pthread_mutex_lock(amp;mut1);
          std::cout<<"ERROR at "<< row[j]
            << " (row " << (row - arr[0])/9
              << " column " << j << ")" << std::endl;
          pthread_mutex_unlock(amp;mut1);
          break;
        }
      }
    }
    pthread_exit((void *) result);
}

int main()
{
  pthread_t id[9];

  pthread_mutex_init(amp;mut1, NULL);

  for (int i = 0; i != 9;   i) {
    if (pthread_create(amp;id[i], NULL, amp;rowCheck, arr[i]) != 0) {
      std::cerr << "error when creating thread " << i << std::endl;
      return -1;
    }
  }

  for (int i = 0; i != 9;   i) {
    void * retval;

    pthread_join(id[i], amp;retval);

    pthread_mutex_lock(amp;mut1);
    std::cout << i << ":" << (char *) retval << std::endl;
    pthread_mutex_unlock(amp;mut1);
  }

  return 0;
}
 

Компиляция и выполнение :

 /tmp % g   -pedantic -Wextra -Wall c.cc -lpthread
/tmp % ./a.out
ERROR at 6 (row 1 column 1)
ERROR at 6 (row 1 column 6)
0:ok
1:ko
2:ok
3:ok
4:ok
5:ok
6:ok
7:ok
8:ok
 

Другой способ — указать индекс через выделенный int, выделенный для каждого потока (и удалить его в потоке) :

 #include <pthread.h>
#include <iostream>

pthread_mutex_t mut1;

int arr[9][9] = {  
                    {6,2,4,5,3,9,1,8,7},
                    {6,6,9,7,2,8,6,3,4},
                    {8,3,7,6,1,4,2,9,5},
                    {1,4,3,8,6,5,7,2,9},
                    {9,5,8,2,4,7,3,6,1},
                    {7,6,2,3,9,1,4,5,8},
                    {3,7,1,9,5,6,8,4,2},
                    {4,9,6,1,8,2,5,7,3},
                    {2,8,5,4,7,3,9,1,6}
                };

void * rowCheck(void* arg)
{
    int rowNum = *((int*) arg);

    delete (int*) arg;

    int * row = arr[rowNum];
    const char * result = "ok";

    for(int i = 0; i < 9; i  ){
      int temp = row[i];
      int count = 0;

      for(int j = i; j < 9; j  ){
        if(row[j] == temp || row[j] <= 0 || row[j] >= 10){
          count  ; 
        }
        if(count > 1){
          result = "ko";
          pthread_mutex_lock(amp;mut1);
          std::cout<<"ERROR at "<< row[j]
            << " (row " << rowNum
              << " column " << j << ")" << std::endl;
          pthread_mutex_unlock(amp;mut1);
          break;
        }
      }
    }
    pthread_exit((void *) result);
}

int main()
{
  pthread_t id[9];

  pthread_mutex_init(amp;mut1, NULL);

  for (int i = 0; i != 9;   i) {
    if (pthread_create(amp;id[i], NULL, amp;rowCheck, new int(i)) != 0) {
      std::cerr << "error when creating thread " << i << std::endl;
      return -1;
    }
  }

  for (int i = 0; i != 9;   i) {
    void * retval;

    pthread_join(id[i], amp;retval);

    pthread_mutex_lock(amp;mut1);
    std::cout << i << ":" << (char *) retval << std::endl;
    pthread_mutex_unlock(amp;mut1);
  }

  return 0;
}