Язык C и многопоточное программирование - PullRequest
2 голосов
/ 03 июня 2011

Мой вопрос связан с программированием потоков на языке C.

Моя проблема в том, что я просто хочу создать два потока в моей программе main.Эти два потока должны работать последовательно, что означает, что мой первый поток должен выполняться первым (никакие другие операторы какого-либо потока не должны выполняться).Первый поток должен иметь полный контроль.Никакие другие операторы какого-либо другого потока, даже main программные операторы, не должны выполняться до тех пор, пока не завершится первый поток.

После завершения первого потока второй поток должен быть выполнен аналогичноfirst.

После этого должен выполняться мой main.

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

Я пишу некоторый код на C следующим образом:

void* fun()
{  
    printf("\nThe thread 1 is running");
}
void* van()
{
    printf("\nthread 2 is running ");
}

int main()
{
    pthread_t t1,t2;
    pthread_create(&t1,NULL,fun,NULL);
    pthread_create(&t2,NULL,van,NULL);
    printf("\nI'm in main\n");
    pthread_join(t2,NULL); 
}

Программа работает отлично, но я не понимаю работу функции pthread_join().

Когда я немного изменяю свой код следующим образом:

int main()
{
    pthread_t t1,t2;
    pthread_create(&t1,NULL,fun,NULL);
    pthread_join(t2,NULL);  // Change
    pthread_create(&t2,NULL,van,NULL);
    printf("\nI'm in main\n");
}

Теперь, когда я запускаю код, он показывает ошибку сегментации.

Теперь мои вопросы следующие:

  1. Что такое параметр атрибута в функции pthread_create()?Почему мы их используем?Каковы атрибуты по умолчанию для потока?Пожалуйста, объясните на примере.
  2. Какой аргумент в функции pthread_create()?Почему мы их используем?Каковы аргументы по умолчанию для потока?Пожалуйста, объясните на примере.
  3. Как на самом деле работает pthread_join()?Что это значит, когда мой код вызывает pthread_join() в основном с t2 в качестве первого аргумента.Означает ли это, что main должен приостановить выполнение до завершения t2 или что-то еще?
  4. Какой второй аргумент в pthread_join()?Почему мы используем это?Каково его значение по умолчанию?Пожалуйста, объясните с примером или кодом.

Ответы [ 4 ]

7 голосов
/ 03 июня 2011
  1. Аргумент attr указывает на структуру pthread_attr_t, содержимое которой используется во время создания потока, чтобы определить атрибуты для нового потока; эта структура инициализируется с использованием pthread_attr_init (3) и связанных функций. Если attr равен NULL, то поток создается с атрибутами по умолчанию ( source ).

  2. Аргумент передается вашей функции потока. Это лучший способ передачи данных в поток (в отличие от использования глобальных переменных, например).

  3. Да, pthread_join ожидает окончания потока. Вот почему ваша программа завершается сбоем, когда вы вызываете pthread_join перед тем, как запустить поток, так как t2 содержит ненужную информацию в этой точке.

  4. Если retval не равен NULL, то pthread_join () копирует состояние выхода целевого потока (то есть значение, которое целевой поток предоставил pthread_exit (3)) в местоположение, на которое указывает * retval. Если целевой поток был отменен, то PTHREAD_CANCELED помещается в * retval. ( источник ).

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

Учитывая это, ваше создание потока может выглядеть так:

struct th_arg{
    ...
};

static void th_work(struct th_arg* a){
     //...some work
    if (success) pthread_exit(EXIT_SUCCESS)
    else pthread_exit(ERROR_CODE);
}

int main(){
     int t1,t2;
     struct th_arg[2];
     int codes[2];
     // initialize th_arg2 
     pthread_create(&t1, NULL, th_work, th_arg+0, th_arg+0);
     pthread_create(&t2, NULL, th_work, th_arg+1, th_arg+1);
     pthread_join(t1, codes+0);
     pthread_join(t2, codes+1);

     if (codes[0] == EXIT_SUCCESS && codes[1] == EXIT_SUCCESS){
             ...
     }
}  
2 голосов
/ 03 июня 2011

Лучший источник для изучения темы posix - https://computing.llnl.gov/tutorials/pthreads/

1 голос
/ 03 июня 2011
  • Атрибут в pthread_create имеет тип pthread_attr_t.Он содержит информацию о потоке, включая информацию о том, где начинается адрес памяти потока и насколько велик его стек.В большинстве случаев вам не нужно использовать этот параметр.

  • Аргумент в pthread_create передается функции start_routine в качестве единственного и единственного аргумента.Это что-то вроде хака.Поскольку указатель может указывать на что угодно (целое число, массив, структуру и т. Д.), Вы можете передать свои аргументы, передав указатель на ВСЕ данные, которые вы хотите передать. В большинстве случаев люди заканчивают тем, что идут сструктура.Для потока нет стандартных аргументов.Если вы не хотите ничего передавать, просто укажите arg как NULL.

Например:

struct arguments
{
    int something;
    char* anotherArg;
    short stillAnotherArg;
}

void* fun(void* arg)
{
    struct arguments *my_args = (struct arguments*)arg;
    printf("You said: %s\n", my_args->anotherArg); // Will print "You said: Hello there"
    ...
}

int main()
{
    pthread_t t1;

    struct arguments my_args;
    my_args.something = 5;
    my_args.anotherArg = "Hello there";
    my_args.stillAnotherArg = 42;

    pthread_create (&t1,NULL,fun, &my_args);
    ...
}
  • pthread_join блокирует вызывающую функцию до завершения указанного потока.

  • Второй аргумент pthread_join позволяет вам захватить возвращаемое значение потока после его выполнения.Каждый из ваших потоков возвращает void*, а второй параметр позволяет вам указать, где будет храниться это возвращаемое значение.

Например:

void* fun(void* arg)
{
    ...
    return NULL; // not very exciting, but I don't want to get
                 // into memory management problems right now
}

int main()
{
    ...

    void* theReturnValue;
    pthread_join(t2, &theReturnValue);

    printf("fun returned %p\n", theReturnValue); // will print "fun returned 0x0"
                                                 // which is NULL
}

Наконец, причина этого segfaults в том, что вы ожидаете поток, который еще не определен.

0 голосов
/ 03 июня 2018

Вы можете использовать библиотеку omp , включив omp.h . Это простой в использовании. Вы можете создать параллельный раздел с помощью директивы

#pragma omp parallel
{
    // PARALLEL Code
}

И установить номера потоков с помощью omp_set_num_threads(2);, а затем получить идентификатор потока с помощью omp_get_thread_num();

Пример:

omp_set_num_threads(2);
#pragma omp parallel
{
    printf("thread %d said hello", omp_get_thread_num());
}
...