Вам может не потребоваться блокировка вообще, если «1 строка на поток» не является строгим требованием, и вы можете иногда доходить до 2 или трех строк. Затем вы можете разделить файл поровну, основываясь на формуле. Предположим, вы хотите прочитать файл в блоках по 1024 килобайта (это может быть и гигабайт): вы разбили его на ядра с приоритетом. Итак:
#define BLOCK_SIZE (1024 * 1024)
#define REGULAR_THREAD_BLOCK_SIZE (BLOCK_SIZE/(2 * NUM_CORES)) // 64kb
#define GPU_THREAD_BLOCK_SIZE (BLOCK_SIZE/2)
- Каждое ядро получает блок 64 КБ
- Ядро 1: смещение 0, размер = REGULAR_THREAD_BLOCK_SIZE
- Ядро 2: смещение 65536, размер = REGULAR_THREAD_BLOCK_SIZE
- Ядро 3: смещение 131072, размер = REGULAR_THREAD_BLOCK_SIZE
- Ядро n: смещение
(n * REGULAR_THREAD_BLOCK_SIZE)
, размер = REGULAR_THREAD_BLOCK_SIZE
- ГП получает 512 КБ, смещение =
(NUM_CORES * REGULAR_THREAD_BLOCK_SIZE)
, размер = GPU_THREAD_BLOCK_SIZE
Так что в идеале они не перекрываются. Однако есть случаи, когда они могут перекрываться. Поскольку вы читаете текстовый файл, строка может попасть в блок следующего ядра. Чтобы избежать дублирования, вы всегда пропускаете первую строку для других ядер и всегда завершаете последнюю строку, если в любом случае следующий поток пропустит ее, вот псевдокод:
void threadProcess(buf, startOFfset, blockSize)
{
int offset = startOffset;
int endOffset = startOffset + blockSize;
if(coreNum > 0) {
// skip to the next line
while(buf[offset] != '\n' && offset < endOffset) offset++;
}
if(offset >= endOffset) return; // nothing left to process
// read number of lines provided in buffer
char *currentLine = allocLineBuffer(); // opening door to security exploits :)
int strPos = 0;
while(offset < endOffset) {
if(buf[offset] == '\n') {
currentLine[strPos] = 0;
processLine(currentLine); // do line processing here
strPos = 0; // fresh start
offset++;
continue;
}
currentLine[strPos] = buf[offset];
offset++;
strPos++;
}
// read the remaineder past the buf
strPos = 0;
while(buf[offset] != '\n') {
currentLine[strPos++] = buf[offset++];
}
currentLine[strPos] = 0;
processLine(currentLine); // process the carryover line
}
Как вы можете видеть, это распараллеливает обработку блока чтения, а не сами чтения. Как вы распараллеливаете чтение? Лучшим, самым удивительным способом было бы отображение в памяти всего блока. Это даст лучшую производительность ввода-вывода, так как это самый низкий уровень.