Как преобразовать * в double/float с помощью pthread, pthread_exit

Мне нужно создать программу, которая вычисляет рекурсию (для определенной последовательности). Когда я использую int и объявляю рекурсию, которая вычисляет значения без плавающих чисел (например, последовательность Фибоначчи, которая возвращает только нейтральные числа), она работает. Однако при попытке использовать последовательности, основанные на делении (с плавающими числами), отображается ошибка, как показано ниже:

ошибка: невозможно преобразовать в плавающий тип pthread_exit((void*)(float)wynik;

Как мне изменить код (или на самом деле функцию *ciag, потому что с ней проблема), чтобы она принимала числа с плавающей запятой?

Функция, которая отлично работает (с int)

int* fibo(int n){

   int wynik;
   int* n1;
   if (n==0) wynik=0;
   else if (n==1) wynik=1;
   else wynik =(int)fibo((int)(n-1))+(int)fibo((int)(n-2));
   return (int*)wynik;
   pthread_exit((void*)wynik);
}

И тот, с которым у меня проблемы (с float, но то же самое происходит, когда я пытаюсь использовать double)

    #include <unistd.h>

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

#define COUNT 2

float *ciag(int n) {
    float wynik;

    if(n == 0)
        wynik = -1;
    else
        wynik = ((float)ciag(n - 1)*(n + 1))/(float)ciag(n - 1)*(float)ciag(n - 1)*(float)ciag(n - 1);

    return(float *)wynik;
    pthread_exit((void *)wynik);
}

void *drugi_watek(void* wynik) {
    int i = 1;  

        while(i == 0) {
        printf("#");
        fflush(stdout);
        usleep(300000);
        pthread_exit((void*)wynik);
    }
}

int main() {
    pthread_t watek_1, watek_2;
    int n;
    float wynik;
    printf("Podaj numer ciagu: ");
    scanf("%d", &n); 

    pthread_create(&watek_1, NULL,(void*)&ciag, n);
    pthread_create(&watek_2, NULL, &drugi_watek, NULL);

    if(!pthread_join(watek_1,(void**)&wynik))
    {
    pthread_cancel(watek_2);
    }

    printf("Element numer %f ciagu: %f\n", &n, &wynik);


    return 0;
}

person Michał    schedule 20.11.2018    source источник


Ответы (1)


Вы не можете напрямую преобразовать float в void * или наоборот.

Самый простой способ сделать это — выделить место для float где-нибудь — либо в куче, либо в стеке вызывающей программы — и заставить функцию потока сохранить значение float в указываемой переменной (float * is легко конвертируется в/из void *). Если вы пойдете по этому пути и разместите значение в стеке, вам нужно убедиться, что кадр стека вызывающей стороны остается существующим до завершения потока.

Поскольку функция, которую вы хотите вызвать, является рекурсивной, использовать ее в качестве функции потока слишком громоздко. Лучше сделать это отдельной (обычной) функцией, которая принимает аргумент int и возвращает float. Затем создайте функцию-оболочку, которая будет целью pthread_create.

А поскольку вам также нужно передать аргумент int в вашу функцию, проще всего выделить struct, чтобы он содержал как аргумент, так и возвращаемое значение (также подойдет union, так как вам на самом деле не нужны аргумент и возвращаемое значение одновременно). Вот пример программы, демонстрирующей шаблон:

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

static float ciag(int n)
{
    float wynik;

    if(n == 0)
        wynik = -1;
    else
        wynik = (ciag(n - 1)*(n + 1))/ciag(n - 1)*ciag(n - 1)*ciag(n - 1);

    return wynik;
}

typedef struct {
    int i;
    float f;
} if_t;

static void *ciag_thread(void *vp)
{
    if_t *ifp = vp;
    // Obtain argument from the structure and put the result back into the structure
    ifp->f = ciag(ifp->i);
    return vp;
}

int main()
{
    pthread_t watek_1;

    int n = 4;

    // Obtain n however you like. Then place argument into structure allocated 
    // on the stack
    if_t arg;
    arg.i = n;

    // Pointer to structure is implicitly convertible to (void *)
    pthread_create(&watek_1, NULL, ciag_thread, &arg);
    pthread_join(watek_1, NULL);
    printf("Thread returned %f\n", arg.f);
    return 0;
}

Еще одно замечание. Ваш код, кажется, предполагает, что pthread_join в первом потоке иногда может дать сбой. Здесь этого не произойдет. Хотя для больших значений n это может занять очень много времени из-за четвертичной природы вашей функции.

person Gil Hamilton    schedule 20.11.2018
comment
Это то, что я имею в виду. Второй поток должен отображать # до тех пор, пока последовательность не будет вычислена. Теперь он работает нормально :) Но как я могу подключить его ко второму потоку (который отображает # и закрывается при вычислении последовательности)? Спасибо за помощь - person Michał; 21.11.2018
comment
пробовал так... pastebin.com/qxb7ukuA но все равно не хотят подключаться и работать вместе - person Michał; 21.11.2018
comment
Два варианта: (1) ваш второй поток следит за переменной флага в своем цикле (начните с переменной с нуля, установите ее в 1, когда ваш первый поток завершится); заставить второй поток выйти из цикла, когда он увидит установленный флаг [этот метод лучше всего, потому что он делает завершение второго потока упорядоченным]; (2) Просто используйте pthread_cancel во втором потоке, когда первый вышел. - person Gil Hamilton; 21.11.2018