반응형

간단한 OpenMP 병렬 프로그래밍 예제를 살펴보자.

 

우선 C/C++ - Language - Open MP Support - Yes (/openmp) 를 선택한다.

 

#include <stdio.h>
#include <omp.h>

int main() {
	// 5개의 스레드로 병렬 영역 실행
	#pragma omp parallel num_threads(5)
	{
		int id = omp_get_thread_num();
		int total = omp_get_num_threads();
		printf("Hello from thread %d out of %d threads\n", id, total);
	}

	return 0;
}

 

 

※ 참고

OpenMP C및 C++ 애플리케이션 프로그램 인터페이스

명령어

런타임 라이브러리 함수

예제

 

반응형
Posted by J-sean
:
반응형

여러 가지 비동기 스레딩을 구현해 보자.

 

우선 인수와 리턴값이 없는 스레드다.

아래 3가지 코드는 모두 같은 내용이지만 다른 방식으로 작성되었다.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Counter()
        {
            int subCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Sub Thread counting... {subCounter++}");
            }
        }

        static void Main(string[] args)
        {
            Task task = new Task(Counter);
            task.Start();
                        
            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");                
            }

            task.Wait();
        }
    }
}

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Action counter = () =>
            {
                int subCounter = 0;
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Sub Thread counting... {subCounter++}");
                }
            };

            Task task = new Task(counter);
            task.Start();
                        
            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");                
            }

            task.Wait();
        }
    }
}

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Task task = Task.Run(() =>
            {
                int subCounter = 0;
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Task counting... {subCounter++}");
                }
            });

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            task.Wait();
        }
    }
}

 

순서는 약간 달라질 수 있다.

 

 

이번엔 인수를 하나 받는 스레드를 만들어 보자. 아래 2가지 코드는 모두 같은 내용이지만 다른 방식으로 작성되었다.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Counter(object to)
        {
            int subCounter = 0;
            for (int i = 0; i < (int)to; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Sub Thread counting... {subCounter++}");
            }
        }

        static void Main(string[] args)
        {
            Task task = new Task(Counter, 5);
            task.Start();

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            task.Wait();
        }
    }
}

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Action<object> Counter = (object to) =>
            {
                int subCounter = 0;
                for (int i = 0; i < (int)to; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Sub Thread counting... {subCounter++}");
                }
            };

            Task task = new Task(Counter, 5);
            task.Start();

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            task.Wait();
        }
    }
}

 

인수가 있는 경우, Task.Run() 메서드에서 람다식으로 코드를 만드는 건 의미가 없는 것 같다.

결과는 위와 같다.

 

 

이번엔 리턴값이 있는 스레드를 만들어 보자. 아래 2가지 코드는 모두 같은 내용이지만 다른 방식으로 작성되었다.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static int Counter()
        {
            int subCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Sub Thread counting... {subCounter++}");
            }

            return subCounter;
        }

        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Counter);
            task.Start();

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            task.Wait();
            Console.WriteLine($"Sub Thread finished with count: {task.Result}");
        }
    }
}

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Task<int> task = Task<int>.Run(() =>
            {
                int subCounter = 0;
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Sub Thread counting... {subCounter++}");
                }

                return subCounter;
            });

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            task.Wait();
            Console.WriteLine($"Sub Thread finished with count: {task.Result}");
        }
    }
}

 

Action은 리턴값이 없는 메서드 전용이기 때문에 이 경우 Action을 사용할 수 없다.

 

순서는 약간 달라질 수 있다.

 

 

이번엔 인수도 있고 리턴값도 있는 스레드를 만들어 보자.

아래 2가지 코드는 모두 같은 내용이지만 다른 방식으로 작성되었다.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static int Counter(object to)
        {
            int subCounter = 0;
            for (int i = 0; i < (int)to; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Sub Thread counting... {subCounter++}");
            }

            return subCounter;
        }

        static void Main(string[] args)
        {
            Task<int> task = new Task<int>(Counter, 5);
            task.Start();

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            task.Wait();
            Console.WriteLine($"Sub Thread finished with count: {task.Result}");
        }
    }
}

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Func<object, int> Counter = (object to) =>
            {
                int subCounter = 0;
                for (int i = 0; i < (int)to; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Sub Thread counting... {subCounter++}");
                }

                return subCounter;
            };

            Task<int> task = new Task<int>(Counter, 5);
            task.Start();

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            task.Wait();
            Console.WriteLine($"Sub Thread finished with count: {task.Result}");
        }
    }
}

 

 

 

async, await를 사용해 보자.

 

아래 코드는 컴파일 에러가 발생한다. Main 함수에는 async가 단순하게 그냥 붙을 수 없다.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
    	// 컴파일 에러 발생
        static async void Main(string[] args)
        {
            await Task.Run(() => Count());

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }
        }

        static void Count()
        {
            int subCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Sub Thread counting... {subCounter++}");
            }

        }
    }
}

 

Main 함수에 단순하게 async가 붙으면 다음과 같은 에러가 발생한다.

Program does not contain a static 'Main' method suitable for an entry point

 

또, 아래와 같이 바꾸면 단일 스레드처럼 동작한다.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            await Task.Run(() => Count());

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }
        }

        static void Count()
        {
            int subCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Sub Thread counting... {subCounter++}");
            }

        }
    }
}

 

 

await 키워드는 이 비동기 작업(서브 스레드)이 완전히 끝날 때까지 여기서 기다리겠다는 의미이기 때문이다.

 

아래와 같이 바꿔보자.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            // await 없이 Task를 실행(시작)만 하고 변수에 담아둔다.
            // 이 시점부터 서브 스레드가 백그라운드에서 동작한다.
            Task countTask = Task.Run(() => Count());

            // 메인 스레드는 멈추지 않고 자신의 루프 작업을 동시에 수행한다.
            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                // 참고: 비동기 메서드(async) 내에서는 Thread.Sleep 대신 await Task.Delay를 사용하는 것을 권장.
                await Task.Delay(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            // 메인 스레드의 작업이 다 끝나면, 메인 프로세스가 종료되기 전에
            // 서브 스레드의 작업이 모두 완료되었는지 마지막으로 확인(대기).
            await countTask;
        }

        static void Count()
        {
            int subCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Sub Thread counting... {subCounter++}");
            }
        }
    }
}

 

아니면 아래와 같이 다른 함수에서 async, await를 사용하도록 코드를 바꾼다.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Count();

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }
        }

        static async void Count()
        {
            await Task.Run(async () =>
            {
                int subCounter = 0;
                for (int i = 0; i < 5; i++)
                {
                    // Use Task.Delay instead of Thread.Sleep to avoid blocking the thread
                    await Task.Delay(1000);
                    Console.WriteLine($"Sub Thread counting... {subCounter++}");
                }
            });
        }
    }
}

 

 

 

이번엔 반환값이 있는 함수를 살펴보자.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Task<int> taskResult = Count();

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }

            int result = taskResult.Result;
            Console.WriteLine($"Result from Sub Thread: {result}");
        }

        static async Task<int> Count()
        {
            return await Task.Run(() =>
            {
                int subCounter = 0;
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Sub Thread counting... {subCounter++}");
                }

                return subCounter;
            });
        }
    }
}

 

 

위 코드를 아래와 같이 바꾸면 단일 스레드처럼 작동하게 된다. 조심하자.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int taskResult = Count().Result;
            // Task가 시작되자마자 바로 Result를 요구하고 있다.
            // 메인 스레드가 진행하지 못하게 된다.
            Console.WriteLine($"Result from Sub Thread: {taskResult}");

            int mainCounter = 0;
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"Main Thread counting... {mainCounter++}");
            }
        }

        static async Task<int> Count()
        {
            return await Task.Run(() =>
            {
                int subCounter = 0;
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"Sub Thread counting... {subCounter++}");
                }

                return subCounter;
            });
        }
    }
}

 

 

 

Parallel 클래스를 사용해서 간편하게 스레드를 사용해 보자.

 

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Parallel.For(0, 10, DoSomething);

            // Alternatively, you can use a lambda expression:
            //Parallel.For(0, 10, i =>
            //{
            //    DoSomething(i);
            //});
        }

        static void DoSomething(int i)
        {
            Thread.Sleep(1000);
            Console.WriteLine($"Job {i} completed.");
        }
    }
}

 

 

하나씩 처리하면 10초가 걸리는 작업이 10개의 스레드가 생성되어 1초 만에 끝난다. (스레드는 CPU 코어의 갯수에 따라 다르게 생성된다)

 

반응형
Posted by J-sean
:
반응형

간단한 멀티 스레드와 뮤텍스 사용 예를 확인해 보자.

 

뮤텍스를 사용하지 않은 멀티스레드.

#include <iostream>
#include <thread>

void counter(int id, int max) {
	for (int i = 0; i < max; i++) {
		std::cout << "id: " << id << ", : " << i << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));	// 1초 대기
	}
}

int main() {
	std::thread t1(counter, 1, 10);
	std::thread t2(counter, 2, 10);

	t1.join();
	t2.join();

	return 0;
}

 

cout 출력 도중 컨텍스트 스위칭이 발생하며 출력이 엉망이 되어 버렸다.

 

뮤텍스를 사용한 멀티스레드.

#include <iostream>
#include <thread>
#include <mutex>

std::mutex m;

void counter(int id, int max) {
	for (int i = 0; i < max; i++) {
		m.lock();
		std::cout << "id: " << id << ", : " << i << std::endl;
		m.unlock();
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

int main() {
	std::thread t1(counter, 1, 10);
	std::thread t2(counter, 2, 10);

	t1.join();
	t2.join();

	return 0;
}

 

출력이 깔끔하다.

 

하지만 위 코드에 나오는 뮤텍스의 lock(), unlock()를 직접 호출하면 안 된다. 뮤텍스 락은 일종의 리소스이기 때문에 거의 대부분 RAII 원칙에 따라 독점적으로 획득된다. 뮤텍스에 락을 정확히 걸거나 해제하는 작업을 쉽게 처리할 수 있는 lock_guard, unique_lock 등의 락 클래스를 사용하자.

 

lock_guard를 사용한 뮤텍스 멀티 스레드.

#include <iostream>
#include <thread>
#include <mutex>

std::mutex m;

void counter(int id, int max) {
	for (int i = 0; i < max; i++) {
		{
			// 락이 필요한 블럭
			std::lock_guard lock(m);
			std::cout << "id: " << id << ", : " << i << std::endl;
		}
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

int main() {
	std::thread t1(counter, 1, 10);
	std::thread t2(counter, 2, 10);

	t1.join();
	t2.join();

	return 0;
}

 

깔끔하고 안전한 출력.

 

반응형
Posted by J-sean
:
반응형

OpenCV와 함께 다수의 물체를 추적해 보자.

 

import cv2
from ultralytics import YOLO

# Load the YOLO26 model
model = YOLO("yolo26n.pt")

# Open the webcam
# cap = cv2.VideoCapture(0)
# cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
# cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
# if cap.set(cv2.CAP_PROP_FPS, 30):
# 	print("FPS set")
# else:
# 	print("FPS setting failed")

cap = cv2.VideoCapture("Cars_On_Highway.mp4")

# Loop through the video frames
while cap.isOpened():
    # Read a frame from the video
    success, frame = cap.read()

    if success:
        # Run YOLO26 tracking on the frame, persisting tracks between frames
        results = model.track(frame, persist=True, verbose=False)

        # Visualize the results on the frame
        annotated_frame = results[0].plot()

        print(f"Number of objects: {len(results[0])}")
        #print(results[0].boxes.id) # (tensor) 바운딩 박스의 track ID를 반환합니다 (사용 가능한 경우).
        #print(results[0].names) # (dict) 클래스 인덱스를 클래스 이름에 매핑하는 사전입니다.
        #print(results[0].boxes.cls) # (tensor) bounding box의 클래스 값을 반환합니다.

        # ID와 각 물체의 클래스 출력
        for id, cls in zip(results[0].boxes.id, results[0].boxes.cls):
            print(f"ID: {id.int()} Class: {results[0].names[cls.int().item()]}", end=', ')
        print()

        # Display the annotated frame
        cv2.imshow("YOLO26 Tracking", annotated_frame)

        # Break the loop if 'q' is pressed
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
    else:
        # Break the loop if the end of the video is reached
        break

# Release the video capture object and close the display window
cap.release()
cv2.destroyAllWindows()

 

웹캠을 사용하거나 원하는 영상을 준비하고 실행한다.

video1.avi
2.41MB
video2.avi
2.15MB

 

 

 

 

캡처하는 시간차 때문에 영상과 콘솔 화면의 출력이 일치하지는 않는다.

 

반응형
Posted by J-sean
:
반응형

한 오브젝트에 여러개의 Shape을 추가해 충돌을 감지해 보자.

XXXShape이나 FixtureDef를 CreateFixture()에 전달하면 충돌 감지기가 추가된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <iostream>
#include "SDL.h"
#include "box2d/box2d.h"
 
class DebugDrawer : public b2Draw
{
public:
    DebugDrawer(SDL_Renderer* renderer) {
        this->renderer = renderer;
    }
private:
    SDL_Renderer* renderer;
    void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {}
    void DrawPoint(const b2Vec2& p, float sizeconst b2Color& color) {}
    void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) {
        SDL_SetRenderDrawColor(renderer, 25500, SDL_ALPHA_OPAQUE);
        SDL_FRect* rect = new SDL_FRect{ vertices[0].x, vertices[0].y, vertices[1].x
            - vertices[0].x, vertices[3].y - vertices[0].y };
        SDL_RenderDrawRectF(renderer, rect);
    }
    void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) {}
    void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) {}
    void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) {}
    void DrawTransform(const b2Transform& xf) {}
};
 
int main(int argc, char* argv[]) {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED, 640480, SDL_WINDOW_RESIZABLE);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -10);
    SDL_Surface* playerSurface = SDL_LoadBMP("player.bmp");
    SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, playerSurface);
 
    // World 정의
    b2Vec2 gravity(0.0f, 9.8f);
    b2World world(gravity);
 
    // DebugDraw 정의
    DebugDrawer* debugDrawer = new DebugDrawer(renderer);
    debugDrawer->SetFlags(b2Draw::e_shapeBit | b2Draw::e_jointBit |
        b2Draw::e_centerOfMassBit | b2Draw::e_aabbBit | b2Draw::e_pairBit);
    world.SetDebugDraw(debugDrawer);
 
    // Player 정의
    b2BodyDef playerBodyDef;
    playerBodyDef.type = b2_dynamicBody;
    playerBodyDef.position.Set(0.0f, 0.0f);
    playerBodyDef.linearVelocity = b2Vec2(50.0f, 0.0f);
    playerBodyDef.angularVelocity = 0.2f;
    b2Body* playerBody = world.CreateBody(&playerBodyDef);
    b2PolygonShape dynamicBox;
    dynamicBox.SetAsBox((float)playerSurface->/ 2, (float)playerSurface->/ 2);
    b2FixtureDef fixtureDef;
    fixtureDef.shape = &dynamicBox;
    fixtureDef.density = 1.0f;
    fixtureDef.friction = 0.3f;
    fixtureDef.restitution = 0.5f;
    playerBody->CreateFixture(&fixtureDef);
    // Player에 shape 추가
    b2PolygonShape another;
    another.SetAsBox(1040, b2Vec2(0-60), 0.0f);
    playerBody->CreateFixture(&another, 1.0f);
    // Creates a fixture from a shape and attach it to this body. This is a convenience function.
    // Use b2FixtureDef if you need to set parameters like friction, restitution, user data, or
    // filtering. If the density is non-zero, this function automatically updates the mass of the body.
    /*
    b2Fixture* temp = NULL;
    for (b2Fixture* fix = playerBody->GetFixtureList(); fix; fix=fix->GetNext()) {
        std::cout << fix->GetFriction() << std::endl;
        if (fix->GetFriction() == 0.2f)
            temp = fix;
        // 여기서 바로 playerBody->DestroyFixture()를 호출하면 fix가 파괴되어 GetNext()를 호출 할 수
        // 없게 된다. 임시 변수에 저장하고 for문을 벗어나면 파괴하자.
    }
    if (temp != NULL)
        playerBody->DestroyFixture(temp);
    // 이 예제에서는 Friction값을 비교해서 삭제할 Fixture를 선택했지만 필요하다면
    // UserData를 설정해서 비교하자.
    */
 
    // Ground 정의
    b2BodyDef groundBodyDef;
    groundBodyDef.position.Set(0.0f, 400.0f);
    b2Body* groundBody = world.CreateBody(&groundBodyDef);
    b2PolygonShape groundBox;
    groundBox.SetAsBox(500.0f, 0.0f);
    SDL_Rect groundRect = { 040050010 };
    groundBody->CreateFixture(&groundBox, 0.0f);
 
    // Wall 정의
    b2BodyDef wallBodyDef;
    wallBodyDef.position.Set(300.0f, 0.0f);
    b2Body* wallBody = world.CreateBody(&wallBodyDef);
    b2PolygonShape wallBox;
    wallBox.SetAsBox(0.0f, 480.0f);
    SDL_Rect wallRect = { 300010480 };
    wallBody->CreateFixture(&wallBox, 0.0f);
 
    float timeStep = 1.0f / 500.0f;
    int velocityIterations = 6;
    int positionIterations = 2;
 
    SDL_Event event;
    bool quit = false;
 
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                quit = true;
                break;
            case SDL_KEYDOWN:
                printf("Key pressed: %s\n", SDL_GetKeyName(event.key.keysym.sym));
                if (event.key.keysym.sym == SDLK_SPACE) {
                    playerBody->SetTransform(b2Vec2(0.0f, 0.0f), 0.0f);
                    playerBody->SetLinearVelocity(b2Vec2(50.0f, 0.0f));
                    playerBody->SetAngularVelocity(0.2f);
                }
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    quit = true;
                break;
 
            default:
                break;
            }
        }
 
        world.Step(timeStep, velocityIterations, positionIterations);
 
        SDL_SetRenderDrawColor(renderer, 255255255, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);
 
        // Ground 그리기
        SDL_SetRenderDrawColor(renderer, 22014020, SDL_ALPHA_OPAQUE);
        SDL_RenderFillRect(renderer, &groundRect);
 
        // Wall 그리기
        SDL_SetRenderDrawColor(renderer, 646464, SDL_ALPHA_OPAQUE);
        SDL_RenderFillRect(renderer, &wallRect);
 
        // Player 그리기        
        b2Vec2 playerPosition = playerBody->GetPosition();
        SDL_Rect destRect = { (int)playerPosition.x - playerSurface->/ 2,
            (int)playerPosition.y - playerSurface->/ 2, playerSurface->w, playerSurface->h };
        SDL_RendererFlip flip = SDL_FLIP_NONE;
        float angle = playerBody->GetAngle() * (180 / (float)M_PI);
        SDL_RenderCopyEx(renderer, texture, NULL&destRect, angle, NULL, flip);
 
        // 가장 마지막에 DebugDraw 그리기
        world.DebugDraw();
 
        SDL_RenderPresent(renderer);
    }
 
    delete debugDrawer;
 
    SDL_DestroyTexture(texture);
    SDL_FreeSurface(playerSurface);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}
 

 

코드를 입력하고 빌드한다.

 

실행하면 공룡의 뿔같은 충돌 감지기가 추가된 모습이 보인다.

 

뿔 처럼 생긴 충돌 감지기는 크기, 위치, Density만 설정되어있다.

 

반응형
Posted by J-sean
:
반응형

스레드 클래스를 상속받는 클래스를 정의하고 사용해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import time
import threading
 
class Worker(threading.Thread):
    def __init__(self, name, count, delay):
        super().__init__()
        self.name = name
        self.count = count
        self.delay = delay
 
    # 스레드 클래스를 상속하는 클래스는 run()를 재정의 해야 한다.
    # 객체를 만들고 start()를 실행하면 run()가 실행된다.
    def run(self):
        print(f"{self.name} job started.")
        for i in range(self.count):
            print(f"{self.name} job: {i}.")
            time.sleep(self.delay)
        print(f"{self.name} job finished.")
 
            
print("Main started.")
 
thread_1 = Worker("First"50.5)
#thread_1.daemon = True
# 데몬 스레드로 설정되면 메인 스레드 종료시 서브 스레드도 종료된다.
thread_1.start()
#thread_1.join()
# join()을 실행한 스레드가 종료할 때까지 나머지 스레드는 대기한다.
 
thread_2 = Worker("Second"50.5)
#thread_2.daemon = True
thread_2.start()
#thread_2.join()
 
print(f"■ Number of threads: {threading.active_count()}")
 
time.sleep(1)
 
print("Main finished.")
 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import time
import threading
 
class Worker(threading.Thread):
    def __init__(self, name, count, delay):
        super().__init__()
        self.name = name
        self.count = count
        self.delay = delay
        
    def run(self):
        print(f"{self.name} job started.")
        for i in range(self.count):
            print(f"{self.name} job: {i}.")
            time.sleep(self.delay)
        print(f"{self.name} job finished.")
 
thread_1 = Worker("First"50.5)
thread_2 = Worker("Second"50.5)
thread_3 = Worker("Third"50.5)
threads = [thread_1, thread_2, thread_3]
 
print(f"■ Number of threads: {threading.active_count()}")
# 활성화된 스레드는 메인스레드 뿐이므로 1이 표시된다.
 
for thread in threads:
    thread.start()
    thread.join()
 

 

 

 

thread - Thread-based parallelism

 

반응형
Posted by J-sean
:
반응형

멀티 스레드를 사용해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time
import threading
 
def Job(name, count, delay):
    print(f"{name} job started.")
    for i in range(count):
        print(f"{name} job: {i}.")
        time.sleep(delay)
    print(f"{name} job finished.")
 
print("Main started.")
 
thread_1 = threading.Thread(target=Job, args=("First"50.5))
thread_1.start()
 
thread_2 = threading.Thread(target=Job, args=("Second"50.5))
thread_2.start()
 
print(f"■ Number of threads: {threading.active_count()}")
 
time.sleep(1)
 
print("Main finished.")
 

 

 

■ threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

- target is the callable object to be invoked by the run() method. Defaults to None, meaning nothing is called.
- args is a list or tuple of arguments for the target invocation. Defaults to ().

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import time
import threading
 
def Job(name, count, delay):
    print(f"{name} job started.")
    for i in range(count):
        print(f"{name} job: {i}.")
        time.sleep(delay)
    print(f"{name} job finished.")
 
print("Main started.")
 
thread_1 = threading.Thread(target=Job, args=("First"50.5))
thread_1.daemon = True
thread_1.start()
 
thread_2 = threading.Thread(target=Job, args=("Second"50.5))
thread_2.daemon = True
thread_2.start()
 
print(f"■ Number of threads: {threading.active_count()}")
 
time.sleep(1)
 
print("Main finished.")
 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import time
import threading
 
def Job(name, count, delay):
    print(f"{name} job started.")
    for i in range(count):
        print(f"{name} job: {i}.")
        time.sleep(delay)
    print(f"{name} job finished.")
 
print("Main started.")
 
thread_1 = threading.Thread(target=Job, args=("First"50.5))
thread_1.start()
thread_1.join()
 
thread_2 = threading.Thread(target=Job, args=("Second"50.5))
thread_2.start()
thread_2.join()
 
print(f"■ Number of threads: {threading.active_count()}")
 
time.sleep(1)
 
print("Main finished.")
 

 

 

■ join(timeout=None)

- Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates – either normally or through an unhandled exception – or until the optional timeout occurs.
- When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call is_alive() after join() to decide whether a timeout happened – if the thread is still alive, the join() call timed out.
- When the timeout argument is not present or None, the operation will block until the thread terminates.
- A thread can be joined many times.

 

 

반응형
Posted by J-sean
:
반응형

It describes how to use the touch API in Android applications.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class MainActivity extends AppCompatActivity {
 
    int[] id = new int[3];
    int[] x = new int[3];
    int[] y = new int[3];
    String result;
 
    TextView textView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        textView = findViewById(R.id.textView);
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
 
        // 3개의 포인터(터치)까지 허용
        int pointer_count = event.getPointerCount();
        if (pointer_count > 3)
            pointer_count = 3;
 
        // ACTION_POINTER_DOWN 과 ACTION_POINTER_UP 이벤트는 액션 값에 추가적인 정보가 인코딩 되어 있다.
        // 액션 값과 MotionEvent.ACTION_POINTER_INDEX_MASK를 & 연산을 하게 되면 눌리거나 떼어진 포인터의 인덱스 값을 알 수 있다.
        // public static final int ACTION_POINTER_INDEX_MASK
        // Bits in the action code that represent a pointer index, used with ACTION_POINTER_DOWN and ACTION_POINTER_UP.
        switch (event.getAction() & MotionEvent.ACTION_MASK)
        {
            case MotionEvent.ACTION_DOWN:
                result = "Single Touch Down:";
                id[0= event.getPointerId(0);
                x[0= (int)event.getX(0);
                y[0= (int)event.getY(0);
                result += "\n(" + x[0+ ", " + y[0+ ")";
                break;
 
            case MotionEvent.ACTION_POINTER_DOWN:
                result = "Multi Touch Down:";
                for (int i = 0; i < pointer_count; i++)
                {
                    id[i] = event.getPointerId(i);
                    x[i] = (int)event.getX(i);
                    y[i] = (int)event.getY(i);
                    result += "\n(" + id[i] + ": " + x[i] + ", " + y[i] + ")";
                }
 
                // Move는 싱글, 멀티 모두 ACTION_MOVE 하나로 처리
            case MotionEvent.ACTION_MOVE:
                result = "Touch Move:";
                for (int i = 0; i < pointer_count; i++)
                {
                    id[i] = event.getPointerId(i);
                    x[i] = (int)event.getX(i);
                    y[i] = (int)event.getY(i);
                    result += "\n(" + id[i] + ": " + x[i] + ", " + y[i] + ")";
                }
                break;
 
            case MotionEvent.ACTION_UP:
                result = "Single Touch Up:";
                id[0= event.getPointerId(0);
                x[0= (int)event.getX(0);
                y[0= (int)event.getY(0);
                result += "\n(" + x[0+ ", " + y[0+ ")";
                break;
 
            case MotionEvent.ACTION_POINTER_UP:
                result = "Multi Touch Up:";
                for (int i = 0; i < pointer_count; i++)
                {
                    id[i] = event.getPointerId(i);
                    x[i] = (int) event.getX(i);
                    y[i] = (int) event.getY(i);
                    result += "\n(" + id[i] + ": " + x[i] + ", " + y[i] + ")";
                }
                break;
 
            default:
                break;
        }
 
        textView.setText(result);
 
        return super.onTouchEvent(event);
    }
}



Run the app and touch the panel.


반응형
Posted by J-sean
: