나는 직렬 디스패치 대기열과 NSCondition
의 조합을 사용합니다. 직렬 대기열은 어떤 쓰기도 동시에 발생하지 않도록하며, NSCondition
은 올바른 순서로 발생하는지 확인합니다. NSCondition
문서에서
: 잠금 주어진 스레드에서 체크 포인트를 모두 같은
조건 개체 역할을합니다. 잠금은 조건을 테스트하는 동안 코드를 보호하고 은 조건에 의해 트리거 된 작업을 수행합니다. 검사 점 동작 은 스레드가 작업으로 진행하기 전에 조건이 참이어야합니다. 조건이 true가 아닌 동안 스레드가 차단됩니다. 나는 이런 식으로 뭔가를 할 거라고 특정 상황에서
... 루프에서
먼저 정의하라 BOOL
(처음 NO
로 설정)하여 프레임이 처리되었는지의 여부를 나타내는있는, 그리고 NSCondition
. 그런 다음 프레임을 처리 할 백그라운드 큐와 데이터를 쓰는 직렬 큐 모두에 dispatch_async
을 입력합니다.
직렬 대기열의 블록이 실행되면 NSCondition
을 잠근 다음 BOOL
을 검사하여 프레임이 처리되었는지 확인하십시오. 있는 경우 쓰기를 진행하십시오. 그렇지 않은 경우 signal
의 경우 wait
을 NSCondition
에서 수신 한 다음 다시 확인하십시오. 완료되면 unlock
NSCondition
입니다.
백그라운드 큐의 블록이 실행되면 NSCondition
을 잠근 후 프레임을 처리하십시오. 프레임이 처리되면 BOOL
을 설정하여 프레임이 처리되었음을 나타냅니다. 그런 다음 signal
및 unlock
NSCondition
입니다.
참고 : 그것은 당신 만 NSCondition
의 잠금 내부 프레임이 처리되고 있음을 나타냅니다 BOOL
하고 outputFrame
에 액세스하는 것이 중요합니다; 자물쇠가 스레드간에 동기화 상태를 유지하는지 확인합니다.
// Create the background and serial queues
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t writeQueue = dispatch_queue_create("writeQueue", DISPATCH_QUEUE_SERIAL);
while (true) { // I'm assuming you have some way to break out of this...
NSCondition *condition = [[NSCondition alloc] init];
// These need the __block attribute so they can be changed inside the blocks
__block BOOL frameProcessed = NO;
__block FrameType outputFrame = nil;
// video >> frame; // read a frame from the video
// dispatch the frame for processing
dispatch_async(backgroundQueue, ^{
[condition lock];
processVideo(frame, outputFrame);
frameProcessed = YES;
[condition signal];
[condition unlock];
});
// dispatch the write
dispatch_async(writeQueue, ^{
[condition lock];
while (!frameProcessed) {
[condition wait]; // this will block the current thread until it gets a signal
}
writeToVideo(outputFrame);
[condition unlock];
});
}
참고 :도 위의 코드에서 BOOL frameProcessed
와 반 미묘한 트릭이있다. 외부 대신 루프 내부에 선언되었으므로 각 블록은 프레임과 연결된 블록을 캡처합니다.
업데이트 :뿐만 아니라 독서에 대한 NSCondition
추가.
비디오에 쓰는 것은 병렬 실행에 비해 느리기 때문에
는 프레임의 엄청나게 할당하고이 디스크에 저장 때까지 메모리에 앉아있다. 나는이 문제를 해결할 것
는 당신이 기다리고 너무 많은 프레임이있는 경우 읽기 블록 다른 NSCondition
이 writeQueue
에 쓸 수 사용 읽어 조절하는 것입니다. 이 개념은 이전에 추가 한 NSCondition
과 거의 동일합니다. 단지 다른 조건 일뿐입니다. 이 캐스트에서 쓸 수있는 프레임 수를 나타내는 int
이됩니다.
루프를 수행하기 전에 readCondition
, writeQueueSize
및 maxWriteQueueSize
을 정의하십시오. 루프 내부에서 먼저 lock
readCondition
을 확인하고 writeQueueSize >= maxWriteQueueSize
을 확인합니다. 그렇지 않은 경우 프레임을 읽고 처리 및 기록을 대기열에 올려 놓으십시오. writeQueue
으로 파견하기 바로 전에 writeQueueSize
을 증분하십시오. 그 다음 unlock
readCondition
.
그리고, 내부 블록은 쓰기가 완료되면, writeQueue
에 lock
readCondition
을 파견 writeQueueSize
및 signal
및 unlock
readCondition
을 감소시킵니다.
이렇게하면 writeQueue
에서 대기중인 블록이 maxWriteQueueSize
개 이상이어야합니다. 대기중인 블록이 많으면 writeQueue
이 준비 될 때까지 비디오에서 프레임 읽기를 효과적으로 일시 중지합니다.
// Create the background and serial queues
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t writeQueue = dispatch_queue_create("writeQueue", DISPATCH_QUEUE_SERIAL);
NSCondition *readCondition = [[NSCondition alloc] init];
__block int writeQueueSize = 0;
const int maxWriteQueueSize = 10;
while (true) { // I'm assuming you have some way to break out of this...
NSCondition *writeCondition = [[NSCondition alloc] init];
// These need the __block attribute so they can be changed inside the blocks
__block BOOL frameProcessed = NO;
__block FrameType outputFrame = nil;
[readCondition lock];
while (writeQueueSize >= maxWriteQueueSize) {
[readCondition wait];
}
// video >> frame; // read a frame from the video
// dispatch the frame for processing
dispatch_async(backgroundQueue, ^{
[writeCondition lock];
processVideo(frame, outputFrame);
frameProcessed = YES;
[writeCondition signal];
[writeCondition unlock];
});
// dispatch the write
writeQueueSize++; // Increment the write queue size here, before the actual dispatch
dispatch_async(writeQueue, ^{
[writeCondition lock];
while (!frameProcessed) {
[writeCondition wait]; // this will block the current thread until it gets a signal
}
writeToVideo(outputFrame);
[writeCondition unlock];
// Decrement the write queue size and signal the readCondition that it changed
[readCondition lock];
writeQueueSize--;
[readCondition signal];
[readCondition unlock];
});
[readCondition unlock];
}
환상적인! 이것은 단순히 훌륭합니다 !!!!!!!!!!!!!!!!!!! 충분히 upvote 수 없습니다 !!!! – SpaceDog
이 방법에는 단 하나의 문제 만 있습니다. 비디오에 대한 쓰기가 병렬 실행에 비해 느리기 때문에 많은 양의 프레임이 할당되고 디스크에 저장 될 때까지 메모리에 저장됩니다. 메모리 사용이 10 초 만에 42Mb에서 2GB로 확대되었습니다! – SpaceDog
내가 도와 줘서 다행이다 :) 나는 당신이 당신의 쓰기 큐를 압도하지 않도록 읽기 속도를 조절하는 방법으로 나의 대답을 업데이트했다. –