mirror of
https://github.com/Kaehvaman/OAIP.git
synced 2025-01-18 08:39:11 +04:00
я не помню что тут было, но коммит надо сделать...
This commit is contained in:
parent
c6e8e7ea44
commit
f2428d8bb6
@ -121,11 +121,11 @@
|
|||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)\include;</AdditionalIncludeDirectories>
|
||||||
<LanguageStandard_C>Default</LanguageStandard_C>
|
<LanguageStandard_C>Default</LanguageStandard_C>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
@ -140,10 +140,12 @@
|
|||||||
<ClInclude Include="..\include\resource_dir.h" />
|
<ClInclude Include="..\include\resource_dir.h" />
|
||||||
<ClInclude Include="..\include\tinyfiledialogs.h" />
|
<ClInclude Include="..\include\tinyfiledialogs.h" />
|
||||||
<ClInclude Include="..\src\game.h" />
|
<ClInclude Include="..\src\game.h" />
|
||||||
|
<ClInclude Include="..\src\parallel_for.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\src\game.c" />
|
<ClCompile Include="..\src\game.c" />
|
||||||
<ClCompile Include="..\src\main.c" />
|
<ClCompile Include="..\src\main.c" />
|
||||||
|
<ClCompile Include="..\src\parallel_for.c" />
|
||||||
<ClCompile Include="..\src\tinyfiledialogs.c" />
|
<ClCompile Include="..\src\tinyfiledialogs.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
<ClInclude Include="..\src\game.h">
|
<ClInclude Include="..\src\game.h">
|
||||||
<Filter>Файлы заголовков</Filter>
|
<Filter>Файлы заголовков</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\parallel_for.h">
|
||||||
|
<Filter>Файлы заголовков</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\src\main.c">
|
<ClCompile Include="..\src\main.c">
|
||||||
@ -44,5 +47,8 @@
|
|||||||
<ClCompile Include="..\src\game.c">
|
<ClCompile Include="..\src\game.c">
|
||||||
<Filter>Исходные файлы</Filter>
|
<Filter>Исходные файлы</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\parallel_for.c">
|
||||||
|
<Filter>Исходные файлы</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -8,12 +8,14 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "parallel_for.h"
|
||||||
|
|
||||||
#define RAYGUI_IMPLEMENTATION
|
#define RAYGUI_IMPLEMENTATION
|
||||||
#include "raygui.h"
|
#include "raygui.h"
|
||||||
|
|
||||||
#define MAP_X 200
|
#define MAP_X 400
|
||||||
#define MAP_Y 100
|
#define MAP_Y 200
|
||||||
#define CELL_SIZE 12
|
#define CELL_SIZE 6
|
||||||
#define FCELL_SIZE (float)CELL_SIZE
|
#define FCELL_SIZE (float)CELL_SIZE
|
||||||
|
|
||||||
#define BOTTOM_BAR_HEIGHT 60
|
#define BOTTOM_BAR_HEIGHT 60
|
||||||
@ -33,7 +35,7 @@ void* SafeMalloc(size_t size)
|
|||||||
{
|
{
|
||||||
void* buffer = malloc(size);
|
void* buffer = malloc(size);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
fprintf(stderr, "Fatal: failed to allocate %zu bytes.\n", size);
|
fprintf(stderr, "Error in SafeMalloc: failed to allocate %zu bytes.\n", size);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
@ -43,7 +45,7 @@ void* SafeCalloc(size_t count, size_t size)
|
|||||||
{
|
{
|
||||||
void* buffer = calloc(count, size);
|
void* buffer = calloc(count, size);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
fprintf(stderr, "Fatal: failed to allocate %zu bytes.\n", count * size);
|
fprintf(stderr, "Error in SafeCalloc: failed to allocate %zu bytes.\n", count * size);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
@ -90,6 +92,37 @@ void celluralAutomata()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//int compute_cell(int x) {
|
||||||
|
// int neighbours = 0;
|
||||||
|
//
|
||||||
|
// neighbours += checkCell(x - 1, y);
|
||||||
|
// neighbours += checkCell(x - 1, y + 1);
|
||||||
|
// neighbours += checkCell(x - 1, y - 1);
|
||||||
|
// neighbours += checkCell(x + 1, y);
|
||||||
|
// neighbours += checkCell(x + 1, y + 1);
|
||||||
|
// neighbours += checkCell(x + 1, y - 1);
|
||||||
|
// neighbours += checkCell(x, y + 1);
|
||||||
|
// neighbours += checkCell(x, y - 1);
|
||||||
|
//
|
||||||
|
// if (neighbours == 3) {
|
||||||
|
// tempMap[x][y] = true;
|
||||||
|
// }
|
||||||
|
// else if (neighbours == 2) {
|
||||||
|
// tempMap[x][y] = map[x][y];
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// tempMap[x][y] = false;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void* compute_cell_forp(void* arg)
|
||||||
|
//{
|
||||||
|
// int* pa = (int*)arg;
|
||||||
|
// int* result = malloc(sizeof(*result));
|
||||||
|
// *result = mult2(*pa);
|
||||||
|
// return result;
|
||||||
|
//}
|
||||||
|
|
||||||
void ClearMap() {
|
void ClearMap() {
|
||||||
for (int x = 0; x < MAP_X; x++) {
|
for (int x = 0; x < MAP_X; x++) {
|
||||||
memset(map[x], 0, MAP_Y * sizeof(bool));
|
memset(map[x], 0, MAP_Y * sizeof(bool));
|
||||||
@ -242,19 +275,25 @@ int main()
|
|||||||
|
|
||||||
DrawFPS(0, MAP_Y * CELL_SIZE);
|
DrawFPS(0, MAP_Y * CELL_SIZE);
|
||||||
DrawText(TextFormat("%.4fx", simSpeed), 0, MAP_Y * CELL_SIZE + 20, 20, ORANGE);
|
DrawText(TextFormat("%.4fx", simSpeed), 0, MAP_Y * CELL_SIZE + 20, 20, ORANGE);
|
||||||
DrawText(TextFormat("%.1f TPS", monitorFPS * simSpeed), 0, MAP_Y * CELL_SIZE + 40, 20, BLUE);
|
DrawText(TextFormat("%.1f TPS", GetFPS() * simSpeed), 0, MAP_Y * CELL_SIZE + 40, 20, BLUE);
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*for (int x = 0; x < MAP_X; x++) {
|
for (int x = 0; x < MAP_X; x++) {
|
||||||
free(map[x]);
|
free(map[x]);
|
||||||
|
free(tempMap[x]);
|
||||||
}
|
}
|
||||||
free(map);*/
|
free(map);
|
||||||
|
free(tempMap);
|
||||||
|
|
||||||
UnloadFont(InconsolataBold);
|
UnloadFont(InconsolataBold);
|
||||||
|
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WinMain() {
|
||||||
|
return main();
|
||||||
}
|
}
|
463
Game of Life/src/parallel_for.c
Normal file
463
Game of Life/src/parallel_for.c
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
#include "parallel_for.h"
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__linux__)
|
||||||
|
#define POSIX
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Platform not supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* A task descriptor specifying the input element and the address at which the *
|
||||||
|
* output element should be stored. *
|
||||||
|
******************************************************************************/
|
||||||
|
typedef struct task_descriptor {
|
||||||
|
void* input_element;
|
||||||
|
void** output_element_address;
|
||||||
|
} task_descriptor;
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* This structure implements a concurrent array-based queue. *
|
||||||
|
************************************************************/
|
||||||
|
typedef struct concurrent_queue {
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
CRITICAL_SECTION criticalSection;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
task_descriptor** array;
|
||||||
|
size_t begin_index;
|
||||||
|
size_t end_index;
|
||||||
|
size_t size;
|
||||||
|
size_t len;
|
||||||
|
} concurrent_queue;
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Initializes the input concurrent queue to an empty state. *
|
||||||
|
************************************************************/
|
||||||
|
static int concurrent_queue_init(concurrent_queue* queue, size_t len)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
queue->array = malloc(len * sizeof(*queue->array));
|
||||||
|
|
||||||
|
if (queue->array == NULL)
|
||||||
|
{
|
||||||
|
return ERROR_FORP_MALLOC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue->begin_index = 0;
|
||||||
|
queue->end_index = 0;
|
||||||
|
queue->size = 0;
|
||||||
|
queue->len = len;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
|
||||||
|
ret = pthread_mutex_init(&queue->mutex, NULL);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
return ERROR_FORP_NO_MUTEX_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
InitializeCriticalSection(&queue->criticalSection);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************
|
||||||
|
* Appends a task descriptor to the tail of the queue. *
|
||||||
|
******************************************************/
|
||||||
|
static void concurrent_queue_enqueue(concurrent_queue* queue,
|
||||||
|
task_descriptor* descriptor)
|
||||||
|
{
|
||||||
|
queue->array[queue->end_index] = descriptor;
|
||||||
|
queue->end_index++;
|
||||||
|
queue->size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Removes the head element from the queue. Unlike all other functions related *
|
||||||
|
* to the queue, this is one is thread-safe. *
|
||||||
|
******************************************************************************/
|
||||||
|
static task_descriptor* concurrent_queue_dequeue(concurrent_queue* queue)
|
||||||
|
{
|
||||||
|
task_descriptor* descriptor;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
pthread_mutex_lock(&queue->mutex);
|
||||||
|
#else
|
||||||
|
EnterCriticalSection(&queue->criticalSection);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (queue->size > 0)
|
||||||
|
{
|
||||||
|
descriptor = queue->array[queue->begin_index];
|
||||||
|
queue->begin_index++;
|
||||||
|
queue->size--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
descriptor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
pthread_mutex_unlock(&queue->mutex);
|
||||||
|
#else
|
||||||
|
LeaveCriticalSection(&queue->criticalSection);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Releases all the resources occupied by the queue, or namely, the mutex and *
|
||||||
|
* the array. *
|
||||||
|
*****************************************************************************/
|
||||||
|
static int concurrent_queue_destroy(concurrent_queue* queue)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < queue->len; i++)
|
||||||
|
{
|
||||||
|
free(queue->array[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(queue->array);
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
ret = pthread_mutex_destroy(&queue->mutex);
|
||||||
|
return ret == 0 ? ERROR_FORP_SUCCESS : ERROR_FORP_NO_MUTEX_DESTROY;
|
||||||
|
#else
|
||||||
|
DeleteCriticalSection(&queue->criticalSection);
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
* Returns the number of processors on Mac OS or Linux. *
|
||||||
|
*******************************************************/
|
||||||
|
static int get_number_of_processors_apple_linux(size_t* p_number_of_processors)
|
||||||
|
{
|
||||||
|
#ifdef POSIX
|
||||||
|
* p_number_of_processors = (size_t)sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* Returns the number of processors on Windows. *
|
||||||
|
***********************************************/
|
||||||
|
static int get_number_of_processors_windows(size_t* p_number_of_processors)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
SYSTEM_INFO si;
|
||||||
|
GetSystemInfo(&si);
|
||||||
|
*p_number_of_processors = (size_t)2 * si.dwNumberOfProcessors;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* A portable function for returning the number of processors. *
|
||||||
|
**************************************************************/
|
||||||
|
static int get_number_of_processors(size_t* p_number_of_processors)
|
||||||
|
{
|
||||||
|
#ifdef POSIX
|
||||||
|
return get_number_of_processors_apple_linux(p_number_of_processors);
|
||||||
|
#else
|
||||||
|
return get_number_of_processors_windows(p_number_of_processors);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Specifies the worker thread arguments. Holds the queue and the function to *
|
||||||
|
* be applied to each queue element. *
|
||||||
|
*****************************************************************************/
|
||||||
|
typedef struct worker_thread_proc_args {
|
||||||
|
concurrent_queue* queue;
|
||||||
|
void* (*func)(void*);
|
||||||
|
int return_status;
|
||||||
|
} worker_thread_proc_args;
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* Implements the worker threads. *
|
||||||
|
*********************************/
|
||||||
|
static void* worker_thread_proc(void* args)
|
||||||
|
{
|
||||||
|
worker_thread_proc_args* worker_thread_proc_arguments =
|
||||||
|
(worker_thread_proc_args*)args;
|
||||||
|
|
||||||
|
concurrent_queue* queue = worker_thread_proc_arguments->queue;
|
||||||
|
void* (*func)(void*) = worker_thread_proc_arguments->func;
|
||||||
|
task_descriptor* task_desc;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
worker_thread_proc_arguments->return_status = ret;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
worker_thread_proc_arguments->return_status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((task_desc = concurrent_queue_dequeue(queue)) != NULL)
|
||||||
|
{
|
||||||
|
*task_desc->output_element_address = func(task_desc->input_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Cancels all the first 'len' threads. *
|
||||||
|
***************************************/
|
||||||
|
#ifdef POSIX
|
||||||
|
static void cancel_threads(pthread_t* pthreads, size_t len)
|
||||||
|
#else
|
||||||
|
static void cancel_threads(HANDLE* threads, size_t len)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
pthread_cancel(pthreads[i]);
|
||||||
|
#else
|
||||||
|
TerminateThread(threads[i], 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
* The actual implementation of the parallel for construct. *
|
||||||
|
***********************************************************/
|
||||||
|
int forp(void** input, void** output, size_t len, void* (*func)(void*))
|
||||||
|
{
|
||||||
|
size_t number_of_cores;
|
||||||
|
size_t szi;
|
||||||
|
int ret;
|
||||||
|
int join_ret = ERROR_FORP_SUCCESS;
|
||||||
|
concurrent_queue queue;
|
||||||
|
task_descriptor* task_desc;
|
||||||
|
worker_thread_proc_args* wtpa;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
|
||||||
|
pthread_t* threads;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
HANDLE* threads;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (input == NULL || output == NULL || func == NULL)
|
||||||
|
{
|
||||||
|
return ERROR_FORP_NO_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
/*****************
|
||||||
|
* Nothing to do. *
|
||||||
|
*****************/
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = get_number_of_processors(&number_of_cores);
|
||||||
|
|
||||||
|
if (ret != ERROR_FORP_SUCCESS)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number_of_cores == 0)
|
||||||
|
{
|
||||||
|
return ERROR_FORP_UNKNOWN_CORES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = concurrent_queue_init(&queue, len)) != ERROR_FORP_SUCCESS)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Create a concurrent queue of tasks. *
|
||||||
|
**************************************/
|
||||||
|
for (szi = 0; szi < len; szi++)
|
||||||
|
{
|
||||||
|
task_desc = malloc(sizeof * task_desc);
|
||||||
|
|
||||||
|
if (task_desc == NULL)
|
||||||
|
{
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_MALLOC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_desc->input_element = input[szi];
|
||||||
|
task_desc->output_element_address = &output[szi];
|
||||||
|
concurrent_queue_enqueue(&queue, task_desc);
|
||||||
|
|
||||||
|
if (ret != ERROR_FORP_SUCCESS)
|
||||||
|
{
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* Create the worker threads. *
|
||||||
|
*****************************/
|
||||||
|
threads = malloc(number_of_cores * sizeof(*threads));
|
||||||
|
|
||||||
|
if (threads == NULL)
|
||||||
|
{
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_MALLOC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wtpa = malloc(number_of_cores * sizeof(*wtpa));
|
||||||
|
|
||||||
|
if (wtpa == NULL)
|
||||||
|
{
|
||||||
|
free(threads);
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_MALLOC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (szi = 0; szi < number_of_cores; szi++)
|
||||||
|
{
|
||||||
|
wtpa[szi].queue = &queue;
|
||||||
|
wtpa[szi].func = func;
|
||||||
|
wtpa[szi].return_status = 0;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
ret = pthread_create(&threads[szi],
|
||||||
|
NULL,
|
||||||
|
worker_thread_proc,
|
||||||
|
&wtpa[szi]);
|
||||||
|
#else
|
||||||
|
threads[szi] = CreateThread(NULL,
|
||||||
|
100000,
|
||||||
|
(LPTHREAD_START_ROUTINE)worker_thread_proc,
|
||||||
|
(LPVOID)&wtpa[szi],
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
cancel_threads(threads, szi);
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_NO_THREAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wtpa[szi].return_status != 0)
|
||||||
|
{
|
||||||
|
cancel_threads(threads, szi + 1);
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_NO_SETCANCELTYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* Wait for all the worker threads to complete. *
|
||||||
|
***********************************************/
|
||||||
|
for (szi = 0; szi < number_of_cores; szi++)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
if (WaitForSingleObject(threads[szi], INFINITE) != 0 && join_ret == 0)
|
||||||
|
{
|
||||||
|
join_ret = ERROR_FORP_NO_JOIN;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
join_ret = pthread_join(threads[szi], NULL);
|
||||||
|
|
||||||
|
if (ret != 0 && join_ret == ERROR_FORP_SUCCESS)
|
||||||
|
{
|
||||||
|
join_ret = ERROR_FORP_NO_JOIN;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return join_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* forp_error(int error_code)
|
||||||
|
{
|
||||||
|
switch (error_code)
|
||||||
|
{
|
||||||
|
case ERROR_FORP_SUCCESS:
|
||||||
|
return "forp succeeded.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_ARGS:
|
||||||
|
return "Some arguments missing.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_JOIN:
|
||||||
|
return "Could not join a thread.";
|
||||||
|
|
||||||
|
case ERROR_FORP_CPU_FEOF:
|
||||||
|
return "Reached EOF while reading the number of processors.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_THREAD:
|
||||||
|
return "Could create a thread.";
|
||||||
|
|
||||||
|
case ERROR_FORP_CPU_FERROR:
|
||||||
|
return "An error occured while reading the number of processors.";
|
||||||
|
|
||||||
|
case ERROR_FORP_POPEN_FAIL:
|
||||||
|
return "Could not execute a program in popen.";
|
||||||
|
|
||||||
|
case ERROR_FORP_MALLOC_FAIL:
|
||||||
|
return "A call to malloc returned NULL.";
|
||||||
|
|
||||||
|
case ERROR_FORP_SSCANF_FAIL:
|
||||||
|
return "sscanf failed.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_MUTEX_INIT:
|
||||||
|
return "Could not initialize a mutex.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_MUTEX_DESTROY:
|
||||||
|
return "Could not destroy a mutex.";
|
||||||
|
|
||||||
|
case ERROR_FORP_UNKNOWN_CORES:
|
||||||
|
return "Could not determine the number of processors.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_SETCANCELTYPE:
|
||||||
|
return "setcanceltype failed.";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "Unknown error code.";
|
||||||
|
}
|
||||||
|
}
|
34
Game of Life/src/parallel_for.h
Normal file
34
Game of Life/src/parallel_for.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef PARALLEL_FOR_H
|
||||||
|
#define PARALLEL_FOR_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define ERROR_FORP_SUCCESS 0
|
||||||
|
#define ERROR_FORP_NO_ARGS 1
|
||||||
|
#define ERROR_FORP_UNKNOWN_CORES 2
|
||||||
|
#define ERROR_FORP_NO_MUTEX_INIT 3
|
||||||
|
#define ERROR_FORP_NO_MUTEX_DESTROY 4
|
||||||
|
#define ERROR_FORP_MALLOC_FAIL 5
|
||||||
|
#define ERROR_FORP_SSCANF_FAIL 6
|
||||||
|
#define ERROR_FORP_POPEN_FAIL 7
|
||||||
|
#define ERROR_FORP_CPU_FEOF 8
|
||||||
|
#define ERROR_FORP_CPU_FERROR 9
|
||||||
|
#define ERROR_FORP_NO_THREAD 10
|
||||||
|
#define ERROR_FORP_NO_SETCANCELTYPE 11
|
||||||
|
#define ERROR_FORP_NO_JOIN 12
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Runs a multithreaded for loop over the input array producing the results and *
|
||||||
|
* storing them in the output array. *
|
||||||
|
*******************************************************************************/
|
||||||
|
int forp(void** input,
|
||||||
|
void** output,
|
||||||
|
size_t len,
|
||||||
|
void* (*func)(void*));
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Returns a human-readable description of an error code related to forp. *
|
||||||
|
*************************************************************************/
|
||||||
|
const char* forp_error(int error_code);
|
||||||
|
|
||||||
|
#endif /* PARALLEL_FOR_H */
|
@ -156,8 +156,6 @@
|
|||||||
<Image Include="..\resources\logo.ico" />
|
<Image Include="..\resources\logo.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\resources\blur.frag" />
|
|
||||||
<None Include="..\resources\blur13.frag" />
|
|
||||||
<None Include="..\resources\watershader.frag" />
|
<None Include="..\resources\watershader.frag" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -65,14 +65,8 @@
|
|||||||
</Image>
|
</Image>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\resources\blur.frag">
|
|
||||||
<Filter>Файлы ресурсов</Filter>
|
|
||||||
</None>
|
|
||||||
<None Include="..\resources\blur13.frag">
|
|
||||||
<Filter>Файлы ресурсов</Filter>
|
|
||||||
</None>
|
|
||||||
<None Include="..\resources\watershader.frag">
|
<None Include="..\resources\watershader.frag">
|
||||||
<Filter>Файлы ресурсов</Filter>
|
<Filter>Исходные файлы</Filter>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -33,7 +33,7 @@ vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction)
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 bumpColor = texture(waterBumpMap, fragTexCoord + sin(seconds / 2.0) / 20.0);
|
vec4 bumpColor = texture(waterBumpMap, fragTexCoord/5 + sin(seconds / 2.0) / 20.0);
|
||||||
bumpColor = (bumpColor + texture(waterBumpMap, fragTexCoord*1.5 + cos(seconds / 2.0) / 20.0)) * 0.5;
|
bumpColor = (bumpColor + texture(waterBumpMap, fragTexCoord*1.5 + cos(seconds / 2.0) / 20.0)) * 0.5;
|
||||||
|
|
||||||
vec2 samplePos = fragTexCoord;
|
vec2 samplePos = fragTexCoord;
|
||||||
|
@ -17,24 +17,30 @@
|
|||||||
#define RAYLIB_NUKLEAR_IMPLEMENTATION
|
#define RAYLIB_NUKLEAR_IMPLEMENTATION
|
||||||
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
|
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
|
||||||
//#define RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS 1
|
//#define RAYLIB_NUKLEAR_DEFAULT_ARC_SEGMENTS 1
|
||||||
//#pragma warning(disable: 4116)
|
#pragma warning(disable: 4116)
|
||||||
#include "raylib-nuklear.h"
|
#include "raylib-nuklear.h"
|
||||||
|
|
||||||
Vector2 scaleDPI = { 1.0f, 1.0f };
|
Vector2 scaleDPI = { 1.0f, 1.0f };
|
||||||
#define M 10
|
#define M 10
|
||||||
#define N 15
|
#define N 15
|
||||||
#define HEIGHT (int)(50 * scaleDPI.y)
|
//#define WIDTH (int)(50 * scaleDPI.x)
|
||||||
#define WIDTH (int)(50 * scaleDPI.x)
|
//#define HEIGHT (int)(50 * scaleDPI.y)
|
||||||
#define VOFFSET (int)(52 * scaleDPI.y)
|
//#define VOFFSET (int)(52 * scaleDPI.y)
|
||||||
|
|
||||||
#define FWIDTH (float)WIDTH
|
//#define FWIDTH (float)WIDTH
|
||||||
#define FHEIGHT (float)HEIGHT
|
//#define FHEIGHT (float)HEIGHT
|
||||||
|
|
||||||
#define PUREBLUE (Color) { 0, 0, 255, 255 }
|
#define PUREBLUE (Color) { 0, 0, 255, 255 }
|
||||||
#define BLACKGRAY (Color) {30, 30, 30, 255}
|
#define BLACKGRAY (Color) {30, 30, 30, 255}
|
||||||
#define VSGREEN (Color) {78, 201, 176, 255}
|
#define VSGREEN (Color) {78, 201, 176, 255}
|
||||||
#define WATERBLUE CLITERAL(Color){200, 240, 255, 255}
|
#define WATERBLUE CLITERAL(Color){200, 240, 255, 255}
|
||||||
|
|
||||||
|
int HEIGHT = 50;
|
||||||
|
int WIDTH = 50;
|
||||||
|
int VOFFSET = 52;
|
||||||
|
float FWIDTH;
|
||||||
|
float FHEIGHT;
|
||||||
|
|
||||||
// Коды ячеек:
|
// Коды ячеек:
|
||||||
// 0 - свободна
|
// 0 - свободна
|
||||||
// 1 -
|
// 1 -
|
||||||
@ -503,15 +509,21 @@ void callNKErrorBoxes(struct nk_context* ctx) {
|
|||||||
#define CPSIZE 213
|
#define CPSIZE 213
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
//SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
//SetConfigFlags(FLAG_WINDOW_HIGHDPI);
|
||||||
|
|
||||||
InitWindow( 1280, 720, "lab16 with raylib");
|
InitWindow(N * WIDTH, M * HEIGHT + VOFFSET, "lab16 with raylib");
|
||||||
scaleDPI = GetWindowScaleDPI();
|
|
||||||
|
|
||||||
int monitor = GetCurrentMonitor();
|
int monitor = GetCurrentMonitor();
|
||||||
int monitorCenterX = GetMonitorWidth(monitor) / 2;
|
int monitorCenterX = GetMonitorWidth(monitor) / 2;
|
||||||
int monitorCenterY = GetMonitorHeight(monitor) / 2;
|
int monitorCenterY = GetMonitorHeight(monitor) / 2;
|
||||||
|
|
||||||
|
scaleDPI = GetWindowScaleDPI();
|
||||||
|
WIDTH = (int)(WIDTH * scaleDPI.x);
|
||||||
|
HEIGHT = (int)(HEIGHT * scaleDPI.y);
|
||||||
|
VOFFSET = (int)(VOFFSET * scaleDPI.y);
|
||||||
|
FWIDTH = (float)WIDTH;
|
||||||
|
FHEIGHT = (float)HEIGHT;
|
||||||
|
|
||||||
int screenWidth = N * WIDTH;
|
int screenWidth = N * WIDTH;
|
||||||
int screenHeight = M * HEIGHT + VOFFSET;
|
int screenHeight = M * HEIGHT + VOFFSET;
|
||||||
float screenWidthF = (float)screenWidth;
|
float screenWidthF = (float)screenWidth;
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.12.35527.113 d17.12
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parallel_for", "parallel_for\parallel_for.vcxproj", "{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}.Release|x64.Build.0 = Release|x64
|
||||||
|
{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{C3792CE7-8D1B-41EB-AB2C-883F1EEF1923}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
@ -0,0 +1,140 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{c3792ce7-8d1b-41eb-ab2c-883f1eef1923}</ProjectGuid>
|
||||||
|
<RootNamespace>parallelfor</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\src\parallel_for.c" />
|
||||||
|
<ClCompile Include="..\src\simpler test.c" />
|
||||||
|
<ClCompile Include="..\src\test.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\src\parallel_for.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Исходные файлы">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Файлы заголовков">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Файлы ресурсов">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\src\parallel_for.c">
|
||||||
|
<Filter>Исходные файлы</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\simpler test.c">
|
||||||
|
<Filter>Исходные файлы</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\test.c">
|
||||||
|
<Filter>Исходные файлы</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\src\parallel_for.h">
|
||||||
|
<Filter>Файлы заголовков</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
463
parallel for loop from stackexchange/src/parallel_for.c
Normal file
463
parallel for loop from stackexchange/src/parallel_for.c
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
#include "parallel_for.h"
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__linux__)
|
||||||
|
#define POSIX
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Platform not supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* A task descriptor specifying the input element and the address at which the *
|
||||||
|
* output element should be stored. *
|
||||||
|
******************************************************************************/
|
||||||
|
typedef struct task_descriptor {
|
||||||
|
void* input_element;
|
||||||
|
void** output_element_address;
|
||||||
|
} task_descriptor;
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* This structure implements a concurrent array-based queue. *
|
||||||
|
************************************************************/
|
||||||
|
typedef struct concurrent_queue {
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
CRITICAL_SECTION criticalSection;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
task_descriptor** array;
|
||||||
|
size_t begin_index;
|
||||||
|
size_t end_index;
|
||||||
|
size_t size;
|
||||||
|
size_t len;
|
||||||
|
} concurrent_queue;
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Initializes the input concurrent queue to an empty state. *
|
||||||
|
************************************************************/
|
||||||
|
static int concurrent_queue_init(concurrent_queue* queue, size_t len)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
queue->array = malloc(len * sizeof(*queue->array));
|
||||||
|
|
||||||
|
if (queue->array == NULL)
|
||||||
|
{
|
||||||
|
return ERROR_FORP_MALLOC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue->begin_index = 0;
|
||||||
|
queue->end_index = 0;
|
||||||
|
queue->size = 0;
|
||||||
|
queue->len = len;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
|
||||||
|
ret = pthread_mutex_init(&queue->mutex, NULL);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
return ERROR_FORP_NO_MUTEX_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
InitializeCriticalSection(&queue->criticalSection);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************
|
||||||
|
* Appends a task descriptor to the tail of the queue. *
|
||||||
|
******************************************************/
|
||||||
|
static void concurrent_queue_enqueue(concurrent_queue* queue,
|
||||||
|
task_descriptor* descriptor)
|
||||||
|
{
|
||||||
|
queue->array[queue->end_index] = descriptor;
|
||||||
|
queue->end_index++;
|
||||||
|
queue->size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Removes the head element from the queue. Unlike all other functions related *
|
||||||
|
* to the queue, this is one is thread-safe. *
|
||||||
|
******************************************************************************/
|
||||||
|
static task_descriptor* concurrent_queue_dequeue(concurrent_queue* queue)
|
||||||
|
{
|
||||||
|
task_descriptor* descriptor;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
pthread_mutex_lock(&queue->mutex);
|
||||||
|
#else
|
||||||
|
EnterCriticalSection(&queue->criticalSection);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (queue->size > 0)
|
||||||
|
{
|
||||||
|
descriptor = queue->array[queue->begin_index];
|
||||||
|
queue->begin_index++;
|
||||||
|
queue->size--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
descriptor = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
pthread_mutex_unlock(&queue->mutex);
|
||||||
|
#else
|
||||||
|
LeaveCriticalSection(&queue->criticalSection);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Releases all the resources occupied by the queue, or namely, the mutex and *
|
||||||
|
* the array. *
|
||||||
|
*****************************************************************************/
|
||||||
|
static int concurrent_queue_destroy(concurrent_queue* queue)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < queue->len; i++)
|
||||||
|
{
|
||||||
|
free(queue->array[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(queue->array);
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
ret = pthread_mutex_destroy(&queue->mutex);
|
||||||
|
return ret == 0 ? ERROR_FORP_SUCCESS : ERROR_FORP_NO_MUTEX_DESTROY;
|
||||||
|
#else
|
||||||
|
DeleteCriticalSection(&queue->criticalSection);
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************
|
||||||
|
* Returns the number of processors on Mac OS or Linux. *
|
||||||
|
*******************************************************/
|
||||||
|
static int get_number_of_processors_apple_linux(size_t* p_number_of_processors)
|
||||||
|
{
|
||||||
|
#ifdef POSIX
|
||||||
|
* p_number_of_processors = (size_t)sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* Returns the number of processors on Windows. *
|
||||||
|
***********************************************/
|
||||||
|
static int get_number_of_processors_windows(size_t* p_number_of_processors)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
SYSTEM_INFO si;
|
||||||
|
GetSystemInfo(&si);
|
||||||
|
*p_number_of_processors = (size_t)2 * si.dwNumberOfProcessors;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* A portable function for returning the number of processors. *
|
||||||
|
**************************************************************/
|
||||||
|
static int get_number_of_processors(size_t* p_number_of_processors)
|
||||||
|
{
|
||||||
|
#ifdef POSIX
|
||||||
|
return get_number_of_processors_apple_linux(p_number_of_processors);
|
||||||
|
#else
|
||||||
|
return get_number_of_processors_windows(p_number_of_processors);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Specifies the worker thread arguments. Holds the queue and the function to *
|
||||||
|
* be applied to each queue element. *
|
||||||
|
*****************************************************************************/
|
||||||
|
typedef struct worker_thread_proc_args {
|
||||||
|
concurrent_queue* queue;
|
||||||
|
void* (*func)(void*);
|
||||||
|
int return_status;
|
||||||
|
} worker_thread_proc_args;
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* Implements the worker threads. *
|
||||||
|
*********************************/
|
||||||
|
static void* worker_thread_proc(void* args)
|
||||||
|
{
|
||||||
|
worker_thread_proc_args* worker_thread_proc_arguments =
|
||||||
|
(worker_thread_proc_args*)args;
|
||||||
|
|
||||||
|
concurrent_queue* queue = worker_thread_proc_arguments->queue;
|
||||||
|
void* (*func)(void*) = worker_thread_proc_arguments->func;
|
||||||
|
task_descriptor* task_desc;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
worker_thread_proc_arguments->return_status = ret;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
worker_thread_proc_arguments->return_status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((task_desc = concurrent_queue_dequeue(queue)) != NULL)
|
||||||
|
{
|
||||||
|
*task_desc->output_element_address = func(task_desc->input_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************
|
||||||
|
* Cancels all the first 'len' threads. *
|
||||||
|
***************************************/
|
||||||
|
#ifdef POSIX
|
||||||
|
static void cancel_threads(pthread_t* pthreads, size_t len)
|
||||||
|
#else
|
||||||
|
static void cancel_threads(HANDLE* threads, size_t len)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
pthread_cancel(pthreads[i]);
|
||||||
|
#else
|
||||||
|
TerminateThread(threads[i], 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
* The actual implementation of the parallel for construct. *
|
||||||
|
***********************************************************/
|
||||||
|
int forp(void** input, void** output, size_t len, void* (*func)(void*))
|
||||||
|
{
|
||||||
|
size_t number_of_cores;
|
||||||
|
size_t szi;
|
||||||
|
int ret;
|
||||||
|
int join_ret = ERROR_FORP_SUCCESS;
|
||||||
|
concurrent_queue queue;
|
||||||
|
task_descriptor* task_desc;
|
||||||
|
worker_thread_proc_args* wtpa;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
|
||||||
|
pthread_t* threads;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
HANDLE* threads;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (input == NULL || output == NULL || func == NULL)
|
||||||
|
{
|
||||||
|
return ERROR_FORP_NO_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
/*****************
|
||||||
|
* Nothing to do. *
|
||||||
|
*****************/
|
||||||
|
return ERROR_FORP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = get_number_of_processors(&number_of_cores);
|
||||||
|
|
||||||
|
if (ret != ERROR_FORP_SUCCESS)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number_of_cores == 0)
|
||||||
|
{
|
||||||
|
return ERROR_FORP_UNKNOWN_CORES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = concurrent_queue_init(&queue, len)) != ERROR_FORP_SUCCESS)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Create a concurrent queue of tasks. *
|
||||||
|
**************************************/
|
||||||
|
for (szi = 0; szi < len; szi++)
|
||||||
|
{
|
||||||
|
task_desc = malloc(sizeof * task_desc);
|
||||||
|
|
||||||
|
if (task_desc == NULL)
|
||||||
|
{
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_MALLOC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_desc->input_element = input[szi];
|
||||||
|
task_desc->output_element_address = &output[szi];
|
||||||
|
concurrent_queue_enqueue(&queue, task_desc);
|
||||||
|
|
||||||
|
if (ret != ERROR_FORP_SUCCESS)
|
||||||
|
{
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* Create the worker threads. *
|
||||||
|
*****************************/
|
||||||
|
threads = malloc(number_of_cores * sizeof(*threads));
|
||||||
|
|
||||||
|
if (threads == NULL)
|
||||||
|
{
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_MALLOC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wtpa = malloc(number_of_cores * sizeof(*wtpa));
|
||||||
|
|
||||||
|
if (wtpa == NULL)
|
||||||
|
{
|
||||||
|
free(threads);
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_MALLOC_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (szi = 0; szi < number_of_cores; szi++)
|
||||||
|
{
|
||||||
|
wtpa[szi].queue = &queue;
|
||||||
|
wtpa[szi].func = func;
|
||||||
|
wtpa[szi].return_status = 0;
|
||||||
|
|
||||||
|
#ifdef POSIX
|
||||||
|
ret = pthread_create(&threads[szi],
|
||||||
|
NULL,
|
||||||
|
worker_thread_proc,
|
||||||
|
&wtpa[szi]);
|
||||||
|
#else
|
||||||
|
threads[szi] = CreateThread(NULL,
|
||||||
|
100000,
|
||||||
|
(LPTHREAD_START_ROUTINE)worker_thread_proc,
|
||||||
|
(LPVOID)&wtpa[szi],
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
cancel_threads(threads, szi);
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_NO_THREAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wtpa[szi].return_status != 0)
|
||||||
|
{
|
||||||
|
cancel_threads(threads, szi + 1);
|
||||||
|
concurrent_queue_destroy(&queue);
|
||||||
|
return ERROR_FORP_NO_SETCANCELTYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************
|
||||||
|
* Wait for all the worker threads to complete. *
|
||||||
|
***********************************************/
|
||||||
|
for (szi = 0; szi < number_of_cores; szi++)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
if (WaitForSingleObject(threads[szi], INFINITE) != 0 && join_ret == 0)
|
||||||
|
{
|
||||||
|
join_ret = ERROR_FORP_NO_JOIN;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
join_ret = pthread_join(threads[szi], NULL);
|
||||||
|
|
||||||
|
if (ret != 0 && join_ret == ERROR_FORP_SUCCESS)
|
||||||
|
{
|
||||||
|
join_ret = ERROR_FORP_NO_JOIN;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return join_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* forp_error(int error_code)
|
||||||
|
{
|
||||||
|
switch (error_code)
|
||||||
|
{
|
||||||
|
case ERROR_FORP_SUCCESS:
|
||||||
|
return "forp succeeded.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_ARGS:
|
||||||
|
return "Some arguments missing.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_JOIN:
|
||||||
|
return "Could not join a thread.";
|
||||||
|
|
||||||
|
case ERROR_FORP_CPU_FEOF:
|
||||||
|
return "Reached EOF while reading the number of processors.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_THREAD:
|
||||||
|
return "Could create a thread.";
|
||||||
|
|
||||||
|
case ERROR_FORP_CPU_FERROR:
|
||||||
|
return "An error occured while reading the number of processors.";
|
||||||
|
|
||||||
|
case ERROR_FORP_POPEN_FAIL:
|
||||||
|
return "Could not execute a program in popen.";
|
||||||
|
|
||||||
|
case ERROR_FORP_MALLOC_FAIL:
|
||||||
|
return "A call to malloc returned NULL.";
|
||||||
|
|
||||||
|
case ERROR_FORP_SSCANF_FAIL:
|
||||||
|
return "sscanf failed.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_MUTEX_INIT:
|
||||||
|
return "Could not initialize a mutex.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_MUTEX_DESTROY:
|
||||||
|
return "Could not destroy a mutex.";
|
||||||
|
|
||||||
|
case ERROR_FORP_UNKNOWN_CORES:
|
||||||
|
return "Could not determine the number of processors.";
|
||||||
|
|
||||||
|
case ERROR_FORP_NO_SETCANCELTYPE:
|
||||||
|
return "setcanceltype failed.";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "Unknown error code.";
|
||||||
|
}
|
||||||
|
}
|
34
parallel for loop from stackexchange/src/parallel_for.h
Normal file
34
parallel for loop from stackexchange/src/parallel_for.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef PARALLEL_FOR_H
|
||||||
|
#define PARALLEL_FOR_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define ERROR_FORP_SUCCESS 0
|
||||||
|
#define ERROR_FORP_NO_ARGS 1
|
||||||
|
#define ERROR_FORP_UNKNOWN_CORES 2
|
||||||
|
#define ERROR_FORP_NO_MUTEX_INIT 3
|
||||||
|
#define ERROR_FORP_NO_MUTEX_DESTROY 4
|
||||||
|
#define ERROR_FORP_MALLOC_FAIL 5
|
||||||
|
#define ERROR_FORP_SSCANF_FAIL 6
|
||||||
|
#define ERROR_FORP_POPEN_FAIL 7
|
||||||
|
#define ERROR_FORP_CPU_FEOF 8
|
||||||
|
#define ERROR_FORP_CPU_FERROR 9
|
||||||
|
#define ERROR_FORP_NO_THREAD 10
|
||||||
|
#define ERROR_FORP_NO_SETCANCELTYPE 11
|
||||||
|
#define ERROR_FORP_NO_JOIN 12
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Runs a multithreaded for loop over the input array producing the results and *
|
||||||
|
* storing them in the output array. *
|
||||||
|
*******************************************************************************/
|
||||||
|
int forp(void** input,
|
||||||
|
void** output,
|
||||||
|
size_t len,
|
||||||
|
void* (*func)(void*));
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Returns a human-readable description of an error code related to forp. *
|
||||||
|
*************************************************************************/
|
||||||
|
const char* forp_error(int error_code);
|
||||||
|
|
||||||
|
#endif /* PARALLEL_FOR_H */
|
33
parallel for loop from stackexchange/src/simpler test.c
Normal file
33
parallel for loop from stackexchange/src/simpler test.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "parallel_for.h"
|
||||||
|
|
||||||
|
int mult2(int x) {
|
||||||
|
return x * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* mult2_parallel(void* arg)
|
||||||
|
{
|
||||||
|
int* pa = (int*) arg;
|
||||||
|
int* result = malloc(sizeof(*result));
|
||||||
|
*result = mult2(*pa);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int nums[4] = { 1, 2, 3, 4 };
|
||||||
|
void* input[4];
|
||||||
|
void* output[4];
|
||||||
|
|
||||||
|
input[0] = &nums[0];
|
||||||
|
input[1] = &nums[1];
|
||||||
|
input[2] = &nums[2];
|
||||||
|
input[3] = &nums[3];
|
||||||
|
|
||||||
|
forp(input, output, 4, mult2_parallel);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
printf("%d\n", *(int*)output[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
137
parallel for loop from stackexchange/src/test.c
Normal file
137
parallel for loop from stackexchange/src/test.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include "parallel_for.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__linux__)
|
||||||
|
#define POSIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(POSIX)
|
||||||
|
#include <sys/time.h>
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#error "Platform not supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* Implements a dummy heavy task. *
|
||||||
|
*********************************/
|
||||||
|
static unsigned long long fibonacci(unsigned long long num)
|
||||||
|
{
|
||||||
|
switch (num)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fibonacci(num - 1) + fibonacci(num - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
* The worker thread procedure. *
|
||||||
|
*******************************/
|
||||||
|
static void* fibonacci_func(void* arg)
|
||||||
|
{
|
||||||
|
unsigned long long* pa = (unsigned long long*) arg;
|
||||||
|
unsigned long long* result = malloc(sizeof(*result));
|
||||||
|
*result = fibonacci(*pa);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Populates randomly the input array. *
|
||||||
|
**************************************/
|
||||||
|
static void populate_input_randomly(void** input_array, size_t len)
|
||||||
|
{
|
||||||
|
unsigned long long* input_datum;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
input_datum = malloc(sizeof(unsigned long long));
|
||||||
|
*input_datum = 20 + rand() % 21;
|
||||||
|
input_array[i] = input_datum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************
|
||||||
|
* Prints the output array. *
|
||||||
|
***************************/
|
||||||
|
static void print_output(void** output, size_t len)
|
||||||
|
{
|
||||||
|
void* raw_datum;
|
||||||
|
unsigned long long datum;
|
||||||
|
size_t i;
|
||||||
|
char* separator = "";
|
||||||
|
printf("[");
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
printf("%s", separator);
|
||||||
|
separator = ", ";
|
||||||
|
raw_datum = output[i];
|
||||||
|
datum = *((unsigned long long*) raw_datum);
|
||||||
|
printf("%llu", datum);
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Returns a current millisecond count. Used for benchmarking. *
|
||||||
|
**************************************************************/
|
||||||
|
static unsigned long long get_milliseconds()
|
||||||
|
{
|
||||||
|
#ifdef POSIX
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return 1000 * tv.tv_sec + tv.tv_usec / 1000;
|
||||||
|
#else
|
||||||
|
return (unsigned long long) GetTickCount64();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define N 100
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
void* input[N];
|
||||||
|
void* output[N];
|
||||||
|
unsigned long long start;
|
||||||
|
unsigned long long end;
|
||||||
|
size_t i;
|
||||||
|
int error_code;
|
||||||
|
|
||||||
|
srand((unsigned int)time(NULL));
|
||||||
|
populate_input_randomly(input, N);
|
||||||
|
|
||||||
|
start = get_milliseconds();
|
||||||
|
error_code = forp(input, output, N, fibonacci_func);
|
||||||
|
end = get_milliseconds();
|
||||||
|
|
||||||
|
print_output(output, N);
|
||||||
|
printf("Parallel for took %llu milliseconds. Error message: %s\n\n",
|
||||||
|
end - start,
|
||||||
|
forp_error(error_code));
|
||||||
|
|
||||||
|
start = get_milliseconds();
|
||||||
|
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
output[i] = fibonacci_func(input[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
end = get_milliseconds();
|
||||||
|
print_output(output, N);
|
||||||
|
printf("Sequential for took %llu milliseconds.\n", end - start);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
getchar();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user