我的应用使用Apple在OSX 10.10上提供的Grand Central Dispatch提供的dispatch_io_read()
和dispatch_io_write()
方法复制文件。
我向用户提供了取消'按钮。我已经使用dispatch_io_close(channel, DISPATCH_IO_STOP)
以各种方式实现了这一点,但是我尝试的每种方法都会导致偶尔崩溃,例如" BUG IN LIBDISPATCH:过度释放对象"," BUIB IN LIBDISPATCH:一个物体的复活"或与保留/释放问题相关的类似崩溃。
如果我只是close()
用户点击“取消”时正在阅读/写入的文件的文件描述符,或者如果我调用dispatch_io_close(channel, DISPATCH_IO_STOP)
,我会遇到相同类型的崩溃来自dispatch_io_read()
和dispatch_io_write()
的清理处理程序。
如何安全取消GCD IO操作?
答案 0 :(得分:0)
以下是使用dispatch io编写cat
的简单替换的示例:
#include <dispatch/dispatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
dispatch_io_t stdin_io = dispatch_io_create(DISPATCH_IO_STREAM, STDIN_FILENO, dispatch_get_main_queue(), ^(int error) {
fprintf(stderr, "Error opening stdin: %d\n", error);
exit(error);
});
dispatch_io_t stdout_io = dispatch_io_create(DISPATCH_IO_STREAM, STDOUT_FILENO, dispatch_get_main_queue(), ^(int error) {
fprintf(stderr, "Error opening stdout: %d\n", error);
exit(error);
});
dispatch_group_t io_completion_group = dispatch_group_create();
dispatch_group_enter(io_completion_group);
dispatch_io_read(stdin_io, 0, SIZE_MAX, dispatch_get_main_queue(), ^(bool done, dispatch_data_t data, int error) {
if (error) {
fprintf(stderr, "Read error: %d\n", error);
exit(error);
}
dispatch_group_enter(io_completion_group);
dispatch_io_write(stdout_io, 0, data, dispatch_get_main_queue(), ^(bool done, dispatch_data_t data, int error) {
if (error) {
fprintf(stderr, "Write error: %d\n", error);
exit(error);
}
if (done) {
dispatch_group_leave(io_completion_group);
}
});
if (done) {
dispatch_group_leave(io_completion_group);
}
});
dispatch_group_notify(io_completion_group, dispatch_get_main_queue(), ^{
dispatch_io_close(stdin_io, 0);
dispatch_release(stdin_io);
dispatch_io_close(stdout_io, 0);
dispatch_release(stdout_io);
dispatch_release(io_completion_group);
exit(0);
});
dispatch_main();
}
希望这可以作为你的起点。
答案 1 :(得分:0)
在读取操作完成之前,您需要使用信号量来阻止关闭;你可以安全地关闭频道。这是一个片段,向您展示如何为写操作执行此操作(尽管它可以很容易地以相同的方式用于读取操作):
size_t length = width * height * 4;
void *tdata = malloc(length);
[texture getBytes:tdata bytesPerRow:rowBytes fromRegion:MTLRegionMake2D(0.0, 0.0, width, height) mipmapLevel:0];
dispatch_data_t data = dispatch_data_create(tdata, length, NULL, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
NSString *outputTextureFileName = [NSString stringWithFormat:@"%lu", frame];
NSString *outputTextureFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"/PinHoleTemp/%@", [outputTextureFileName stringByAppendingPathExtension:@"dat"]]];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_io_t write_channel = dispatch_io_create_with_path(DISPATCH_IO_STREAM, [outputTextureFilePath UTF8String], 1, O_WRONLY, dispatch_get_global_queue(0, 0), ^(int error) {
});
dispatch_io_write(write_channel, 0, data, dispatch_get_global_queue(0, 0), ^(bool done, dispatch_data_t _Nullable data, int error) {
if (done) NSLog(@"Finished writing data to file");
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_io_close(write_channel, 0);
此示例在每次摄像机获取视频帧时将包含Metal纹理的数据文件写入指定URL的文件。创建纹理后,它将转换为dispatch_data_t对象。然后,创建一个信号量,用于阻止任何创建和打开新通道并写入操作直到完成。在dispatch_io_write完成处理程序发出信号量信号后,代码将执行dispatch_io_close块。