Hello again Laurent,
Thanks for your very valuable help. I have now been able to write an OpenMP-parallelized program that will be just what I need for my physical simulation.
Instead of declaring a sf::Window object in each thread, I instead use a pointer, and take care to not use the contructor of the object simultaneously. This is possible to do with OpenMP by means of the line #pragma omp critical.
Now I think it works beautifully. Compiling without -fopenmp will result in a program that is for just one processsor. I have chosen to specify the number of threads to use as a command line parameter. I run the program as e.g. "openmp.elf 3" to get three threads.
SFML is certainly good for visualizing simulations like the one I am working on, and it is very elegant. My simulation calculates a path-integral by means of the Monte Carlo method. In this context, path-integral means the integral of a function over a path-space, in this case a space of closed paths.
So I construct a lot of polygon paths, and add up certain contributions as the simulations runs. It is important to be able to see the polygons at least when debugging, because that is a very good way to discover problems with the algorithm.
Thanks again for your help,
Torquil Sørensen
Here is some OpenMP-parallelized SFML code:
#include <SFML/Window.hpp>
#include <iostream>
using namespace std;
#ifdef _OPENMP
extern "C" {
int omp_get_thread_num();
int omp_set_num_threads(int);
int omp_get_num_threads();
}
#endif
GLint* mkDispList() {
GLint* dispList = new GLint;
*dispList = glGenLists(1);
const double l = 1.0;
const double xmin = -l, xmax = l, ymin = -l, ymax = l, zmin = -l, zmax = l;
glNewList(*dispList, GL_COMPILE);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_LOOP);
glVertex3f(xmin, ymin, zmin); glVertex3f(xmax, ymin, zmin);
glVertex3f(xmax, ymax, zmin); glVertex3f(xmin, ymax, zmin);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(xmin, ymin, zmax); glVertex3f(xmax, ymin, zmax);
glVertex3f(xmax, ymax, zmax); glVertex3f(xmin, ymax, zmax);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(xmax, ymax, zmin); glVertex3f(xmax, ymax, zmax);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(xmin, ymax, zmin); glVertex3f(xmin, ymax, zmax);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(xmin, ymin, zmin); glVertex3f(xmin, ymin, zmax);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3f(xmax, ymin, zmin); glVertex3f(xmax, ymin, zmax);
glEnd();
glEndList();
return(dispList);
}
int main(int argc, char** argv)
{
const int wInit = 320, hInit = 240;
#ifdef _OPENMP
cout << "Using OpenMP with " << atoi(argv[1]) << " thread(s)" << endl;
omp_set_num_threads(atoi(argv[1]));
#else
cout << "Not using OpenMP. There will only be one thread" << endl;
#endif
#pragma omp parallel
{
sf::Window* Win;
int threadNum = 0;
#ifdef _OPENMP
threadNum = omp_get_thread_num();
#endif
float sphCamPos[3];
sphCamPos[0] = 5.0; sphCamPos[1] = 0.0; sphCamPos[2] = 0.0;
#pragma omp critical
{
Win = new sf::Window(sf::VideoMode(wInit, hInit, 32), "Window");
cout << "Thread " << threadNum << " has created its window" << endl;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, wInit, hInit);
gluPerspective(45, float(wInit)/hInit, 1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
#pragma omp barrier
GLint* dispList = mkDispList();
usleep(100000);
#pragma omp barrier
for(int f = 0; f != 1000; ++f) {
cout << "Thread " << threadNum << " is simulating" << endl;
// Do simulation here
usleep(10000);
// Plot
#pragma omp critical
{
if(Win->IsOpened()) {
cout << "Thread " << threadNum << " is plotting its frame " << f << endl;
Win->SetActive(true);
sf::Event Event;
while(Win->GetEvent(Event)) {
if(Event.Type == sf::Event::Closed) {
Win->Close();
}
if((Event.Type == sf::Event::KeyPressed)
&&(Event.Key.Code == sf::Key::Escape)) {
Win->Close();
}
}
// Plot simulation state
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glCallList(*dispList);
Win->Display();
Win->SetActive(false);
}
}
}
}
return(0);
}