Im currently trying to code a timer on a D1 mini that has three tactile switches and will display on a 64x48 OLED display, switch 1 and 2 will increase and decrease the time and 3 will start the time you have put in.
As of now when as it turns on the timer is in a stopped state and you can set your desired time input with switch 1 and 2 and then start the timer with switch 3 but when the timer counts down I want it to stop at 00:00 for you to then input a new time with switch 1 and 2 and then start it again with switch 3. The timer keeps going and does not appear to stop at 00:00.
Here is the code:
#include <Wire.h>
#include <Adafruit_SSD1306.h>
// SCL GPIO5
// SDA GPIO4
#define OLED_RESET 0 // GPIO0
Adafruit_SSD1306 display(OLED_RESET);
int switch1 = D3;
int switch2 = D4;
int switch3 = D5;
int minutes = 0;
int seconds = 0;
int originalMinutesValue = 0;
int originalSecondsValue = 0;
bool timerRunning = false;
bool isReset = false;
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(4,16);
pinMode(switch1, INPUT);
pinMode(switch2, INPUT);
pinMode(switch3, INPUT);
originalMinutesValue = minutes;
originalSecondsValue = seconds;
}
void loop() {
if(digitalRead(switch1) == LOW) {
if(seconds == 0) {
if(minutes > 0) {
minutes--;
seconds = 59;
}
} else {
seconds--;
}
delay(200);
}
if(digitalRead(switch2) == LOW) {
if(seconds == 59) {
minutes++;
seconds = 0;
} else {
seconds++;
}
delay(200);
}
if(digitalRead(switch3) == LOW) {
timerRunning = !timerRunning;
if(timerRunning && !isReset) {
isReset = true;
}
delay(200);
}
if(timerRunning){
if(seconds==0){
if(minutes>0){
minutes--;
seconds=59;
}else{
if(isReset){
minutes = originalMinutesValue;
seconds = originalSecondsValue;
isReset = false;
}else {
timerRunning = false;
}
}
}else{
seconds--;
}
delay(1000);
}
display.clearDisplay();
display.setCursor(4,16);
if(minutes < 10) {
display.print("0");
}
display.print(minutes);
display.print(":");
if(seconds < 10) {
display.print("0");
}
display.print(seconds);
display.display();
}
I have tried a lot of different workarounds but cannot get it to work. Please let me know if you might know the problem.
I am writing a scheduling algorithm while studying the Operating System.
And 'fopen_s' was used to receive information about the process from a 'txt' file.
First, I checked the function's output with 'errno_t', and it was normal with '0'.
However, if I try to execute it, an error such as an image appears and cannot proceed. Where did the error occur?
This code was written in Visual Studio 2017 using the c language.
This is 'process.txt'. (All are integers.)
1 1 0 10 3
1 2 0 1 1
1 3 0 2 4
1 4 0 5 2
2 5 0 5 2
2 6 0 4 3
2 7 0 1 2
2 8 0 7 1
3 9 0 5 2
3 10 0 4 3
3 11 0 1 4
3 12 0 6 1
This is the core code that causes the error.
int main()
{
sem_init(&semaphore, 0, 1);
q1 = (Process *)malloc(sizeof(Process) * 100);
q2 = (Process *)malloc(sizeof(Process) * 100);
q3 = (Process *)malloc(sizeof(Process) * 100);
FILE *fpp = NULL;
errno_t err = fopen_s(&fpp, "sample.txt", "r");
if (fpp = NULL)
{
printf("OPEN ERROR\n");
return 0;
}
while (!feof(fpp))
{
fscanf_s(fpp, "%d %d %d %d %d",
&class_num, &sub_id, &sub_arrive_time, &sub_burst, &sub_priority);
if (class_num == 1)
{
q1[i_q1].id = sub_id;
q1[i_q1].arrive_time = sub_arrive_time;
q1[i_q1].burst = sub_burst;
q1[i_q1].priority = sub_priority;
i_q1++;
}
else if (class_num = 2)
{
q2[i_q2].id = sub_id;
q2[i_q2].arrive_time = sub_arrive_time;
q2[i_q2].burst = sub_burst;
q2[i_q2].priority = sub_priority;
i_q2++;
}
else if (class_num = 3)
{
q3[i_q3].id = sub_id;
q3[i_q3].arrive_time = sub_arrive_time;
q3[i_q3].burst = sub_burst;
q3[i_q3].priority = sub_priority;
i_q3++;
}
p_count++;
}//초기화 완료
pthread_create(&thread[idx], NULL, MLQS, NULL);//별도의 함수 만들어서 넣기
pthread_join(thread[idx], NULL);
fclose(fpp);
free(q1);
free(q2);
free(q3);
system("pause");
return 0;
}
This is the full code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <pthread.h>
#include <semaphore.h>
#define TRUE 1
#define FALSE 0
typedef struct _process {
int id;
int arrive_time;
int waiting_time;
int return_time;
int turnaround_time;
int response_time;
int burst;
int priority;
int completed;
}Process;
//쓰레드 동기화를 동기화를 위한 semaphore
sem_t semaphore;
int process_count = 0;
int p_count = 0;
int i_q1 = 0;
int i_q2 = 0;
int i_q3 = 0;
int class_num;
int sub_id;
int sub_arrive_time;
int sub_burst;
int sub_priority;
Process *q1;
Process *q2;
Process *q3;
int idx = 0;
pthread_t thread[5];
int time_quantum = 2;
//프로세스 초기화
void p_init(Process p[], int length)
{
int i;
for (i = 0; i < length; i++)
{
p[i].waiting_time = 0;
p[i].return_time = 0;
p[i].response_time = 0;
p[i].completed = FALSE;
}
}
int all_completed(Process *p1, Process *p2, Process *p3, int q1_len, int q2_len, int q3_len)
{
int i;
for (i = 0; i < q1_len; i++)
{
if (p1[i].completed == FALSE)
return FALSE;
}
for (i = 0; i < q2_len; i++)
{
if (p2[i].completed == FALSE)
return FALSE;
}
for (i = 0; i < q2_len; i++)
{
if (p3[i].completed == FALSE)
return FALSE;
}
return TRUE;
}
void print_table(Process p[], int n)
{
int i;
// 반복문에서 사용할 변수 선언
puts("\t+-----+------------+-------------+----------+-------------+-----------------+--------------+-----------------+");
puts("\t| PID | Burst Time | Arrive Time | Priority | Return Time | Response Time | Waiting Time | Turnaround Time |");
puts("\t+-----+------------+-------------+----------+-------------+-----------------+--------------+-----------------+");
/* 프로세스 갯수만큼 반복하며 포맷을 맞추어 출력 */
for (i = 0; i < n; i++)
{
printf("\t| %3d | %3d | %3d | %3d | %3d | %3d | %3d | %3d |\n",
p[i].id, p[i].burst, p[i].arrive_time, p[i].priority, p[i].return_time, p[i].response_time, p[i].waiting_time, p[i].turnaround_time);
puts("\t+-----+------------+-------------+----------+-------------+-----------------+--------------+-----------------+");
}
puts("\n");
}
// 반환 시간을 비교하는 함수
int compare_by_return_time(const void *a, const void *b)
{
Process *pA = (Process *)a;
Process *pB = (Process *)b;
/* pA의 반환 시간이 작을 경우 */
if (pA->return_time < pB->return_time)
return -1;
/* ptA의 반환 시간이 클 경우 */
else if (pA->return_time > pB->return_time)
return 1;
/* 반환 시간이 같을 경우 -> 존재 X */
else
return 0;
}
// 반환 시간을 퀵 소트 기반으로 정렬한다.
void quick_sort_by_return_time(Process p[], int len)
{
qsort(p, len, sizeof(Process), compare_by_return_time);
}
// 우선 순위를 비교하는 함수
int compare_by_priority(Process *a, Process *b)
{
Process *pA = (Process *)a;
Process *pB = (Process *)b;
if (a->priority == b->priority) {
if (a->burst != b->burst) {
if (a->burst < b->burst)
return -1;
else
return 1;
}
else
return 0;
}
else {
if (a->priority < b->priority)
return -1;
else if (a->priority > b->priority)
return 1;
}
}
void quick_sort_by_priority_time()
{
qsort(q1, i_q1, sizeof(Process), compare_by_priority);
}
void gantt_chart(Process p[], int len)
{
int i, j; // 반복문에 사용할 변수
printf("\t ");
for (i = 0; i < len; i++)
{
for (j = 0; j < p[i].burst; j++)
printf("--");
printf(" ");
}
printf("\n\t|");
for (i = 0; i < len; i++)
{
for (j = 0; j < p[i].burst - 1; j++)
printf(" ");
printf("%d", p[i].id);
for (j = 0; j < p[i].burst - 1; j++)
printf(" ");
printf("|");
}
printf("\n\t ");
for (i = 0; i < len; i++)
{
for (j = 0; j < p[i].burst; j++)
printf("--");
printf(" ");
}
printf("\n\t");
printf("0");
for (i = 0; i < len; i++)
{
for (j = 0; j < p[i].burst; j++)
printf(" ");
if (p[i].return_time > 9)
printf("\b");
printf("%d", p[i].return_time);
}
printf("\n");
}
//**************************************************//
// Q1 : Non-preemptive Priority Scheduling Algorithm
// 알고리즘 시간 계산 함수
void Cal_for_npps(Process p[], int len)
{
int i, j; // 반복문에 사용할 변수
int check; // 모든 프로세스 완료 여부 확인
int min; // Priority가 가장 높은 index 저장
int time = 0; // 현재 시간
p[0].return_time = p[0].burst;
p[0].turnaround_time = p[0].return_time - p[0].arrive_time;
p[0].response_time = 0;
p[0].completed = TRUE;
time = p[0].burst;
while (TRUE)//모든 프로세스 완료 시 종료
{
min = INT_MAX;
check = FALSE;
for (i = 1; i < len; i++)//Priority가 가장 높은 프로세스 탐색
{
if ((p[min].priority > p[i].priority) && (p[i].completed == FALSE))
{//현재 Priority보다 작은 Priority 가졌지만 실행되지 않았다면 갱신
min = i;
check = TRUE;
}
}
if (check == FALSE)//모든 프로세스 완료 시 반복문 탈출
break;
p[min].response_time = time - p[min].arrive_time;
p[min].return_time = time + p[min].burst;
p[min].turnaround_time = p[min].return_time - p[min].arrive_time;
p[min].waiting_time = time - p[min].arrive_time;
p[min].completed = TRUE;
time += p[min].burst;
}
}
void *NPPS(void *arg)
{
int i; // 반복문에 사용할 변수
int total_waiting_time = 0;
int total_turnaround_time = 0;
int total_response_time = 0;
p_init(q1, i_q1);
quick_sort_by_priority_time();
Cal_for_npps(q1, i_q1);
for (i = 0; i < i_q1; i++)
{
total_waiting_time += q1[i].waiting_time;
total_turnaround_time += q1[i].turnaround_time;
total_response_time += q1[i].response_time;
}
quick_sort_by_return_time(q1, i_q1);
printf("\tNon-preemptive Priority Scheduling Algorithm\n\n");
gantt_chart(q1, i_q1);
printf("\n\tAverage Waiting Time : %-2.2lf\n", (double)total_waiting_time / (double)i_q1);
printf("\tAverage Turnaround Time : %-2.2lf\n", (double)total_turnaround_time / (double)i_q1);
printf("\tAverage Response Time : %-2.2lf\n\n", (double)total_response_time / (double)i_q1);
print_table(q1, i_q1);
}
//**************************************************//
// Q2 : HRN(Highest Response-Ratio Next)
void *HRN(void *arg)
{
int i, j; // 반복문에 사용할 변수
int time, locate; // 현재 시간과 프로세스 위치
int total_burst_time = 0;
int total_waiting_time = 0;
int total_turnaround_time = 0;
int total_response_time = 0;
float hrr, temp; // 우선순위 저장
p_init(q2, i_q2);
for (i = 0; i < i_q2; i++)
{
total_burst_time += q2[i].burst;
}
for (time = q2[0].arrive_time; time < total_burst_time;)
{
hrr = -99999;
for (i = 0; i < i_q2; i++)// Priority가 가장 높은 프로세스 탐색
{
if (q2[i].completed != TRUE)
{
temp = (q2[i].burst + (time - q2[i].arrive_time)) / q2[i].burst;
if (hrr < temp)//우선순위 갱신
{
hrr = temp;
locate = i;
}
}
}
time += q2[locate].burst;
q2[locate].waiting_time = time - q2[locate].arrive_time - q2[locate].burst;
q2[locate].turnaround_time = time - q2[locate].arrive_time;
q2[locate].return_time = q2[locate].turnaround_time + q2[locate].arrive_time;
q2[locate].response_time = q2[locate].waiting_time;
q2[locate].completed = TRUE;
total_waiting_time += q2[locate].waiting_time;
total_turnaround_time += q2[locate].turnaround_time;
total_response_time += q2[locate].response_time;
}
quick_sort_by_return_time(q2, i_q2);
printf("\tHighest Response Ratio Next Scheduling Algorithm\n\n");
gantt_chart(q2, i_q2);
printf("\n\tAverage Waiting Time : %-2.2lf\n", (double)total_waiting_time / (double)i_q2);
printf("\tAverage Turnaround Time : %-2.2lf\n", (double)total_turnaround_time / (double)i_q2);
printf("\tAverage Response Time : %-2.2lf\n\n", (double)total_response_time / (double)i_q2);
print_table(q2, i_q2);
}
void cal_for_sjf(Process *p, int len)
{
int i, j; // 반복문에 사용할 변수
int cur_time = 0; // 현재 시간
int min = 0; // 최소 시간을 갖는 인덱스 저장
p[0].completed = TRUE;
p[0].return_time = p[0].burst;
p[0].turnaround_time = p[0].burst - p[0].arrive_time;
p[0].waiting_time = 0;
cur_time = p[0].burst;
for (i = 1; i < len; i++)
{
for (j = 1; j < len; j++)
{
if (p[j].completed == TRUE)
continue;
else
{
min = j;
break;
}
}
for (j = 1; j < len; j++)
{
if ((p[j].completed == FALSE) && (p[j].burst < p[min].burst))
{
min = j;
}
}
p[min].waiting_time = cur_time - p[min].arrive_time;
p[min].completed = TRUE;
cur_time += p[min].burst;
p[min].return_time = cur_time;
p[min].turnaround_time = p[min].return_time - p[min].arrive_time;
}
}
void *SJF(void *arg)
{
int i;
int total_waiting_time = 0;
int total_turnaround_time = 0;
int total_response_time = 0;
p_init(q3, i_q3);
cal_for_sjf(q3, i_q3);
for (i = 0; i < i_q3; i++)
{
q3[i].return_time = q3[i].turnaround_time + q3[i].arrive_time;
q3[i].response_time = q3[i].waiting_time;
total_waiting_time += q3[i].waiting_time;
total_turnaround_time += q3[i].turnaround_time;
total_response_time += q3[i].response_time;
}
printf("\tSJF Scheduling Algorithms\n\n");
quick_sort_by_return_time(q3, i_q3);
gantt_chart(q3, i_q3);
printf("\n\tAverage Waiting Time : %-2.2lf\n", (double)total_waiting_time / (double)i_q3);
printf("\tAverage Turnaround Time : %-2.2lf\n", (double)total_turnaround_time / (double)i_q3);
printf("\tAverage Response Time : %-2.2lf\n\n", (double)total_response_time / (double)i_q3);
print_table(q3, i_q3);
}
void *MLQS(void *arg)
{
idx++;
while (all_completed(q1, q2, q3, i_q1, i_q2, i_q3)) {
sem_wait(&semaphore);
if (idx == 1) {
pthread_create(&thread[idx], NULL, NPPS, NULL);
pthread_join(thread[idx], NULL);
}
else if (idx == 2) {
pthread_create(&thread[idx], NULL, HRN, NULL);
pthread_join(thread[idx], NULL);
}
else if (idx == 3) {
pthread_create(&thread[idx], NULL, SJF, NULL);
pthread_join(thread[idx], NULL);
}
idx++;
sem_post(&semaphore);
if (idx > 3)
idx = 1;
}
}
int main()
{
sem_init(&semaphore, 0, 1);
q1 = (Process *)malloc(sizeof(Process) * 100);
q2 = (Process *)malloc(sizeof(Process) * 100);
q3 = (Process *)malloc(sizeof(Process) * 100);
FILE *fpp = NULL;
errno_t err = fopen_s(&fpp, "sample.txt", "r");
if (fpp = NULL)
{
printf("OPEN ERROR\n");
return 0;
}
while (!feof(fpp))
{
fscanf_s(fpp, "%d %d %d %d %d",
&class_num, &sub_id, &sub_arrive_time, &sub_burst, &sub_priority);
if (class_num == 1)
{
q1[i_q1].id = sub_id;
q1[i_q1].arrive_time = sub_arrive_time;
q1[i_q1].burst = sub_burst;
q1[i_q1].priority = sub_priority;
i_q1++;
}
else if (class_num = 2)
{
q2[i_q2].id = sub_id;
q2[i_q2].arrive_time = sub_arrive_time;
q2[i_q2].burst = sub_burst;
q2[i_q2].priority = sub_priority;
i_q2++;
}
else if (class_num = 3)
{
q3[i_q3].id = sub_id;
q3[i_q3].arrive_time = sub_arrive_time;
q3[i_q3].burst = sub_burst;
q3[i_q3].priority = sub_priority;
i_q3++;
}
p_count++;
}//초기화 완료
pthread_create(&thread[idx], NULL, MLQS, NULL);//별도의 함수 만들어서 넣기
pthread_join(thread[idx], NULL);
fclose(fpp);
free(q1);
free(q2);
free(q3);
system("pause");
return 0;
}
Beside all the issues mentioned in the comments:
if (fpp = NULL)
assigns NULL to ffp instead of comparing it (and the condition is always false). You mean
if (fpp == NULL)
I have some problems with transmiting and receiving using usart. First informations that I want transmit are writen to circle buffer. Then indormations are send but some informations are lost.
Variables
enum {
BUF_SIZE = 100
};
char BUF_T[BUF_SIZE], BUF_R[BUF_SIZE];
uint8_t R_EMPTY = 0, R_BUSY = 0, T_EMPTY = 0, T_BUSY = 0;
Transmiting
void Send(void) {
uint8_t index = T_EMPTY;
for (int i = 0; i < 10; i++) {
BUF_T[index] = i+'0';
index++;
if (index >= BUF_SIZE) {
index = 0;
}
}
__disable_irq();
if (T_BUSY == T_EMPTY
&& __HAL_UART_GET_FLAG(&huart2,UART_FLAG_TXE) == SET) {
T_EMPTY = index;
T_BUSY++;
uint8_t tmp = BUF_T[T_BUSY];
if (T_BUSY >= BUF_SIZE) {
T_BUSY = 0;
}
HAL_UART_Transmit_IT(&huart2, (uint8_t*) &tmp, 1);
} else {
T_EMPTY = index;
}
__enable_irq();
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
//if (huart->Instance == USART2) {
if (T_BUSY != T_EMPTY) {
__disable_irq();
T_BUSY++;
uint8_t tmp = BUF_T[T_BUSY];
if (T_BUSY >= BUF_SIZE) {
T_BUSY = 0;
}
HAL_UART_Transmit_IT(&huart2, (uint8_t*) &tmp, 1);
__enable_irq();
}else {
Send();
}
//}
}
Screen from hterm
On picture can be seen that from time to time one char is lost. I don't understant why?
Regarding receiving can somebody tell mi if it OK?
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
//if (huart->Instance == USART2) {
uint8_t tmp = BUF_R[R_EMPTY];
R_EMPTY++;
if (R_EMPTY >= BUF_SIZE) {
R_EMPTY = 0;
}
HAL_UART_Receive_IT(&huart2, (uint8_t*) &tmp, 1);
//}
}
OK ive searched about for quite some time now but i simply cannot find a replacement for the GetKeyState() function in linux. All i need and want is to simply poll the arrow keys, and if they are pressed, execute something. My home PC is linux based and my students' PC is windows based, so when i worked in that, i wrote this code:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <dos.h>
#include <windows.h>
int x; int y, redraw;
int i; int l, xm, ym, op, as, b, ab;
short int display[10][10];
void draw() {
if (redraw == 1) {
system("cls");
while (l < 10) {
while (i<10) {
if (display[i][l] == 0) { printf("="); }
if (display[i][l] == 1) { printf("X"); }
if (display[i][l] == 2) { printf("w"); }
if (display[i][l] == 3) { printf("0"); }
if (display[i][l] == 4) { printf("#"); }
if (display[i][l] == 5) { printf("M"); }
if (display[i][l] == 6) { printf("H"); }
if (display[i][l] == 7) { printf("8"); }
printf("|");
i++;
}
i = 0;
printf("\n");
printf("-+-+-+-+-+-+-+-+-+-+");
printf("\n");
l++;
}
l = 0;
redraw = 0;
}
}
void getkeys() {
while (b == 0) {
if (GetKeyState(VK_LEFT) & 0x8000)
{
xm = -1;
b = 1;
}
if (GetKeyState(VK_RIGHT) & 0x8000)
{
xm = 1;
b = 1;
}
if (GetKeyState(VK_UP) & 0x8000)
{
ym = -1;
b = 1;
}
if (GetKeyState(VK_DOWN) & 0x8000)
{
ym = 1;
b = 1;
}
if (GetKeyState(VK_BACK) & 0x8000)
{
op = -1;
b = 1;
}
if (GetKeyState(VK_RETURN) & 0x8000)
{
op = 1;
b = 1;
}
} b = 0; redraw = 1;
}
void cursor() {
display[x][y] = as;
x = x + xm;
xm = 0;
y = y + ym;
ym = 0;
if (x >9) { x = 0; }
if (y >9) { y = 0; }
if (x <0) { x = 9; }
if (y <0) { y = 9; }
ab = display[x][y];
as = ab;
if (as == 0) {
display[x][y] = 4;
}
if (as == 1) {
display[x][y] = 5;
}
if (as == 2) {
display[x][y] = 6;
}
if (as == 3) {
display[x][y] = 7;
}
Sleep(100);
}
void main()
{
while (i < 10) {
while (l<10) { display[l][i] = rand() % 4; l++; } l = 0; i++;
}
redraw = 1;
while (1) {
draw();
getkeys();
b = 0;
cursor();
}
}
now this basically prints an array and a cursor on it, but it does use the GetKeyState() function and i just can not find an alternative to it on linux. So is there any simple alternative to the mentioned function and is it possible to make the source code multiplatform somehow? Thanks in advance.
I need to calculate PI using multiple threads for my homework. The problem is -- when using more than one thread, most of the time the sum is calculated incorrectly (smaller than it should be). I've spent quite some time on figuring it out, so maybe I'm overlooking something obvious. Hoping for your help.
P.S. There was a question about the same task. However, my mistake is different.
Here is my code.
#include <stdio.h>
#include <Windows.h>
#include <ctime>
#define THREAD_COUNT 2
#define N 10000000
#define BLOCK_SIZE 43087
typedef struct {
unsigned startPos;
int threadInd;
double threadSum;
bool isCalculating;
} ThreadArg;
HANDLE* threads;
HANDLE* events;
DWORD WINAPI ThreadProc(LPVOID);
void calculate(double* sum, unsigned start);
int main() {
unsigned cursor = 0;
ThreadArg* params = NULL;
threads = NULL;
if (THREAD_COUNT > 1) {
params = (ThreadArg*)malloc(sizeof(ThreadArg)*(THREAD_COUNT - 1));
threads = (HANDLE*)malloc(sizeof(HANDLE)*(THREAD_COUNT - 1));
events = (HANDLE*)malloc(sizeof(HANDLE)*(THREAD_COUNT - 1));
}
for (int i = 0; i < THREAD_COUNT - 1; ++i) {
ThreadArg arg;
arg.isCalculating = true;
arg.startPos = cursor;
arg.threadInd = i;
arg.threadSum = 0;
params[i] = arg;
threads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)(¶ms[i]), CREATE_SUSPENDED, 0);
events[i] = CreateEvent(NULL, TRUE, TRUE, NULL);
cursor += BLOCK_SIZE;
}
unsigned startTime = clock();
for (int i = 0; i < THREAD_COUNT - 1; ++i) {
ResumeThread(threads[i]);
}
double mainSum = 0;
while (cursor < N) {
for (int i = 0; i < THREAD_COUNT - 1; ++i) {
if (!params[i].isCalculating) {
params[i].startPos = cursor;
SetEvent(events[i]);
cursor += BLOCK_SIZE;
}
}
calculate(&mainSum, cursor);
cursor += BLOCK_SIZE;
}
bool allFinished;
do {
allFinished = true;
for (int i = 0; i < THREAD_COUNT - 1; ++i) {
if (params[i].isCalculating) {
allFinished = false;
break;
}
}
} while(!allFinished);
for (int i = 0; i < THREAD_COUNT - 1; ++i) {
mainSum += params[i].threadSum;
CloseHandle(threads[i]);
}
printf("Time: %d\n", clock() - startTime);
printf("PI = %.7f\n", mainSum/N);
free(threads);
free(params);
system("pause");
}
DWORD WINAPI ThreadProc(LPVOID lParam) {
ThreadArg* param = (ThreadArg*)lParam;
while (true) {
ResetEvent(events[param->threadInd]);
calculate(¶m->threadSum, param->startPos);
InterlockedDecrement((LONG*)¶m->isCalculating);
WaitForSingleObject(events[param->threadInd], INFINITE);
InterlockedIncrement((LONG*)¶m->isCalculating);
}
}
void calculate(double* sum, unsigned start) {
int endLoop = start + BLOCK_SIZE;
double x;
for (unsigned i = start; i < endLoop; ++i) {
if (i < N) {
x = (i + 0.5) / N;
*sum += 4 / (1 + x*x);
} else break;
}
}
you not need events at all. working thread never must wait. all can be done with interlocked operations.
class CALC_TASK
{
C_ASSERT(sizeof(double)==sizeof(__int64));
union {
double _sum;
__int64 _value;
};
double _step;
LONG _startPos, _maxPos, _blockSize;
static double calculate(LONG i, LONG count, double step)
{
double x, sum = 0.0;
do
{
x = (i-- - 0.5) * step;
sum += 4.0 / (1.0 + x*x);
} while (--count);
return step * sum;
}
void add(double x)
{
union {
double sum;
__int64 value;
};
union {
double new_sum;
__int64 new_value;
};
sum = _sum;
for ( ; ; value = new_value)
{
new_sum = sum + x;
new_value = _InterlockedCompareExchange64(&_value, new_value, value);
if (new_value == value)
{
return;
}
}
}
BOOL getBlock(LONG& pos, LONG& count)
{
LONG startPos, newPos, curPos;
for (startPos = _startPos ; startPos < _maxPos; startPos = curPos)
{
if ((newPos = startPos + _blockSize) > _maxPos)
{
newPos = _maxPos;
}
curPos = _InterlockedCompareExchange(&_startPos, newPos, startPos);
if (curPos == startPos)
{
pos = newPos, count = newPos - startPos;
return TRUE;
}
}
return FALSE;
}
void calculateEx()
{
LONG i, count;
double step = _step;
while (getBlock(i, count))
{
add(calculate(i, count, step));
}
}
public:
double getsum()
{
return _sum;
}
CALC_TASK(LONG maxPos, LONG blockSize)
{
_startPos = 0, _blockSize = blockSize, _maxPos = maxPos, _sum = 0.0, _step = 1.0 / (double)maxPos;
}
static DWORD CALLBACK ThreadProc(PVOID pct)
{
reinterpret_cast<CALC_TASK*>(pct)->calculateEx();
return 0;
}
};
double test(LONG maxPos, LONG blockSize)
{
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
PHANDLE phThreads = 0;
ULONG nThreads = 0;
CALC_TASK ct(maxPos, blockSize);
if (1 < si.dwNumberOfProcessors)
{
ULONG n = si.dwNumberOfProcessors - 1;
phThreads = (HANDLE*)alloca(n * sizeof(HANDLE));
do
{
if (*phThreads = CreateThread(NULL, PAGE_SIZE, CALC_TASK::ThreadProc, &ct, 0, 0))
{
nThreads++, phThreads++;
}
} while (--n);
}
CALC_TASK::ThreadProc(&ct);
if (nThreads)
{
WaitForMultipleObjects(nThreads, phThreads - nThreads, TRUE, INFINITE);
do
{
CloseHandle(*--phThreads);
} while (--nThreads);
}
return ct.getsum();
}
void testEx()
{
ULONG dwStart = GetTickCount();
double d = test(0x10000000, 0x8000);
dwStart = GetTickCount() - dwStart;
DbgPrint("pi = %.15f, %u milliseconds\n", d, dwStart);
}
in my test with 8 core/treads it take ~ 0.5 second for 0x10000000 steps. with single thread this take ~3.5 seconds.
as alternative you can use openMP
double calculateOMP(int num_steps)
{
double x, sum = 0.0, step = 1.0 / (double) num_steps;
#pragma omp parallel for reduction(+:sum) private(x)
for (int i = num_steps; i > 0; --i)
{
x = (i - 0.5) * step;
sum += 4.0 / (1.0 + x*x);
}
return step * sum;
}
for this you need use /openmp option and add vcomp.lib to linker input