Как эффективно многопоточность алгоритма?
Я иду прямо к делу. У меня есть этот код:
while (inputLength > 0)
{
if (mode == MODE_AES_ENCRYPT)
aesni_ecb_encrypt(ctx, input + shift, 16, output + shift);
else if (mode == MODE_AES_DECRYPT)
aesni_ecb_decrypt(ctx, input + shift, 16, output + shift);
shift += 16;
inputLength -= 16;
}
Он выполняет шифрование AES-ECB для одного 16-байтового блока на входе и сохраняет результат на выходе. Параметр ctx является структурой, которая содержит число раундов и подразделов для шифрования.
Шифрование AES-ECB теоретически можно распараллелить, поэтому я попытался использовать многопоточность кода следующим образом:
typedef struct
{
AES_Context* Ctx;
unsigned char* input;
unsigned char* output;
_Bool done;
} threadInfos;
unsigned long WINAPI ThreadFunc(threadInfos* data)
{
aes_ecb_encrypt(data->Ctx, data->input, data->output);
data->done = 1;
}
while (inputLength > 0)
{
threadInfos info1; info1.done = 0; info1.Ctx = ctx;
threadInfos info2; info2.done = 0; info2.Ctx = ctx;
threadInfos info3; info3.done = 0; info3.Ctx = ctx;
threadInfos info4; info4.done = 0; info4.Ctx = ctx;
info1.input = (input + shift); info1.output = (output + shift);
info2.input = (input + shift + 16); info2.output = (output + shift + 16);
info3.input = (input + shift + 32); info3.output = (output + shift + 32);
info4.input = (input + shift + 48); info4.output = (output + shift + 48);
CreateThread(NULL, 0, ThreadFunc, &info1, 0, NULL);
CreateThread(NULL, 0, ThreadFunc, &info2, 0, NULL);
CreateThread(NULL, 0, ThreadFunc, &info3, 0, NULL);
CreateThread(NULL, 0, ThreadFunc, &info4, 0, NULL);
while (info1.done == 0 || info2.done == 0 || info3.done == 0 || info4.done == 0)
;
shift += 64;
inputLength -= 64;
}
и вот результаты с точки зрения скорости:
Вывод тот же, что означает, что моя многопоточность работает, однако она крайне неэффективна, поскольку она в 1000 раз медленнее...
И вот мой вопрос. Как я могу использовать многопоточность шифрования в 4 или 8 потоках - в зависимости от возможностей процессора - но таким образом, чтобы он был быстрее, а не в 1000 раз медленнее?
1 ответ
Проблема в том, что вы создаете поток для выполнения одного блока алгоритма AES, а затем уничтожаете его снова. Как вы заметили, это в 1000 раз медленнее. Все ваше время тратится на создание и уничтожение потоков.
Что вам нужно сделать, это создать потоки один раз в начале, а затем каждый из них будет работать как часть всех блоков. Например, поток 0 выполняет все блоки с блоком% 4 == 0, поток 1 выполняет все блоки с блоком% 4 == 1 и так далее.
Замечания: _Bool done;
не является потокобезопасным. Например, на ARM ваш цикл ожидания может никогда не завершиться.