Oh, line 47 was to avoid an obfuscation of the code. Well, I suppose it failed that purpose if you're asking. It's because writing that many pointers to pointers was annoying. Obviously, my allocation procedure is pretty inelegant but that wasn't the purpose of my code. What I wanted to do was, create a routine that would use multiple threads to traverse independent parts of a tree and identify leaves.
You see, I have this plan, right? It's pretty amazing. The general gist I get from the meshing community is that insertion > other methods. Construction has its own merits but the big thing seems to be insertion or at least, my hero Volker Springel was all like, "Oh yeah, I'ma stick it in... that tetrahedron!" with his code Arepo which is tetrahedral mesh + physics 'n' stuffs.
Idk how he does his stuff, but it basically works like this, for every insertion in a tetrahedron, 4 children are created. Granted, there are special cases of this but the number of children is capped off at 4. There is no such thing as going from 1 to 5, at least not directly.
So, what I want to do is, create a quadtree of pointers and traverse the poop out of it, searching for valid insertion spots and start counting. Doing this single-threaded is kind of slow so I want to quadruple thread it because all I have is 4 cores. But I'll write it to scale with more cores later. I'm hoping it'll be easy to do with pthreads but eh. Even though I graduated, my account on the school's super computer is still active and I think they've hyperthreaded it so I have 32 threads available. Or they gave me two CPUs, Idk.
And yes, I know about work-load balance and I'm trying to work on that but omg, it's a tough problem.
Either way, I took Salem's advice and he forgot to mention the most important detail, the use of pthread_join because for like 15 minutes, I was nerd raging beyond all belief.
So, I must say, thank you very much, Salem and now my code works perfectly all the time. Though I have encountered a race condition in that the second thread will sometimes finish before the first. I know there's a semaphore solution to this or is it a mutex? I think a mutex is like a lock on a structure to prevent two threads from acting on the same data but a semaphore makes sure a thread is finished before another one is, right? But when I compile with the world's longest command, "gcc -g -Wall -Wextra -lpthread -std=c11 -o tree tree.c", it works perfectly.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
struct node {
int index;
struct node *parent;
struct node *children[2];
};
void traverse(struct node *tree) {
if (!tree) return;
traverse(tree->children[0]);
if (!tree->children[0] && !tree->children[1]) printf("%d\n", tree->index);
traverse(tree->children[1]);
}
void *shear(void *t) {
traverse(t);
return NULL;
}
struct node* buildTree(void) {
struct node *root = malloc(sizeof(*root));
for (int i=0; i<2; i++) {
root->children[i] = malloc(sizeof(*root));
for (int j=0; j<2; j++) {
root->children[i]->children[j] = malloc(sizeof(*root));
for (int k=0; k<2; k++) {
struct node *tmp = root->children[i]->children[j]->children[k];
tmp = malloc(sizeof(*root));
tmp->index = 4*i+2*j+k;
tmp->children[0] = NULL;
tmp->children[1] = NULL;
root->children[i]->children[j]->children[k] = tmp;
}
}
}
return root;
}
int main(void) {
struct node *root = buildTree();
pthread_t shears[2];
pthread_create(&shears[0], NULL, shear, root->children[0]);
pthread_create(&shears[1], NULL, shear, root->children[1]);
pthread_join(shears[0], NULL);
pthread_join(shears[1], NULL);
return 0;
}
Note that I call traverse from the side for easier control. Dealing with thread returns is annoying as balls and keeping traverse separate should allow for easier manipulations. Ty again for all the help