下面是我正在使用的當前代碼。當我注釋掉運行progress_bar 函式的代碼時,代碼按預期完美運行,mandelbrot 列印到單獨的影像檔案中。然而,無論出于何種原因,當我嘗試包含該功能時,當程式的其余部分完成時,它會突然停止一切。如何在沒有程式鎖定到偽死鎖狀態的情況下包含 progress_bar 函式?任何和所有的幫助表示贊賞。
#include <cstdint>
#include <cstdlib>
#include <complex>
#include <fstream>
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
// Import things we need from the standard library
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::complex;
using std::cout;
using std::endl;
using std::ofstream;
// Define the alias "the_clock" for the clock type we're going to use.
typedef std::chrono::steady_clock the_clock;
// The size of the image to generate.
const int WIDTH = 1920;
const int HEIGHT = 1200;
// The number of times to iterate before we assume that a point isn't in the
// Mandelbrot set.
// (You may need to turn this up if you zoom further into the set.)
const int MAX_ITERATIONS = 500;
// The image data.
// Each pixel is represented as 0xRRGGBB.
uint32_t image[HEIGHT][WIDTH];
double progress;
bool progressDone = false;
std::mutex locking;
std::condition_variable conditionMet;
int partsDone = 0;
// Write the image to a TGA file with the given name.
// Format specification: http://www.gamers.org/dEngine/quake3/TGA.txt
void progress_bar() {
std::unique_lock<std::mutex> lock(locking);
while (!progressDone) {
//std::this_thread::sleep_for(std::chrono::nanoseconds(100));
cout << "Current Progress is at: " << progress << "%\n";
conditionMet.wait(lock);
}
cout << "Mandelbrot is finished! Take a look.";
}
void write_tga(const char *filename)
{
ofstream outfile(filename, ofstream::binary);
uint8_t header[18] = {
0, // no image ID
0, // no colour map
2, // uncompressed 24-bit image
0, 0, 0, 0, 0, // empty colour map specification
0, 0, // X origin
0, 0, // Y origin
WIDTH & 0xFF, (WIDTH >> 8) & 0xFF, // width
HEIGHT & 0xFF, (HEIGHT >> 8) & 0xFF, // height
24, // bits per pixel
0, // image descriptor
};
outfile.write((const char *)header, 18);
for (int y = 0; y < HEIGHT; y)
{
for (int x = 0; x < WIDTH; x)
{
uint8_t pixel[3] = {
image[y][x] & 0xFF, // blue channel
(image[y][x] >> 8) & 0xFF, // green channel
(image[y][x] >> 16) & 0xFF, // red channel
};
outfile.write((const char *)pixel, 3);
}
}
outfile.close();
if (!outfile)
{
// An error has occurred at some point since we opened the file.
cout << "Error writing to " << filename << endl;
exit(1);
}
}
// Render the Mandelbrot set into the image array.
// The parameters specify the region on the complex plane to plot.
void compute_mandelbrot(double left, double right, double top, double bottom, double start, double finish)
{
for (int y = start; y < finish; y)
{
for (int x = 0; x < WIDTH; x)
{
// Work out the point in the complex plane that
// corresponds to this pixel in the output image.
complex<double> c(left (x * (right - left) / WIDTH),
top (y * (bottom - top) / HEIGHT));
// Start off z at (0, 0).
complex<double> z(0.0, 0.0);
// Iterate z = z^2 c until z moves more than 2 units
// away from (0, 0), or we've iterated too many times.
int iterations = 0;
while (abs(z) < 2.0 && iterations < MAX_ITERATIONS)
{
z = (z * z) c;
iterations;
}
if (iterations == MAX_ITERATIONS)
{
// z didn't escape from the circle.
// This point is in the Mandelbrot set.
image[y][x] = 0x000000; // black
}
else if (iterations == 0) {
image[y][x] = 0xFFFFFF;
}
else
{
// z escaped within less than MAX_ITERATIONS
// iterations. This point isn't in the set.
image[y][x] = 0xFFFFFF; // white
image[y][x] = 16711680 | iterations << 8 | iterations;
}
std::unique_lock<std::mutex> lock(locking);
progress = double((1.0 / (WIDTH*HEIGHT)) * 100.0);
conditionMet.notify_one();
}
}
partsDone = 1;
}
int main(int argc, char *argv[])
{
cout << "Please wait..." << endl;
// Start timing
std::vector<std::thread*> threads;
the_clock::time_point start = the_clock::now();
std::thread progressive(progress_bar);
for (int slice = 0; slice < 2; slice ) {
// This shows the whole set.
threads.push_back(new std::thread(compute_mandelbrot, -2.0, 1.0, 1.125, -1.125, HEIGHT * (slice / 2), HEIGHT * ((slice 1) / 2)));
// This zooms in on an interesting bit of detail.
//compute_mandelbrot(-0.751085, -0.734975, 0.118378, 0.134488, 0, HEIGHT/16);
}
// Stop timing
for (std::thread* t : threads) {
t->join();
delete t;
}
if (partsDone == 2) {
progressDone = true;
}
progressive.join();
the_clock::time_point end = the_clock::now();
// Compute the difference between the two times in milliseconds
auto time_taken = duration_cast<milliseconds>(end - start).count();
cout << "Computing the Mandelbrot set took " << time_taken << " ms." << endl;
write_tga("output.tga");
std::this_thread::sleep_for(milliseconds(3000));
return 0;
}```
uj5u.com熱心網友回復:
您不終止的原因是在所有作業完成后沒有人通知進度條執行緒。conditionMet.notify_one();在呼叫之前添加progressive.join(). 我在下面的Demo中省略了 IO 以便能夠在在線編譯器中運行。另外(正如@GoswinvonBrederlow 在評論中提到的那樣)確保partsDone變成std::atomic,因為如果> 1 個執行緒呼叫partsDone = 1你最終會得到未定義的結果,反過來你將無法判斷你的程式是否完成。
如果您將進度更改為 std::atomic 并讓您的進度列印機僅以 100 毫秒的間隔加載變數(并列印在上一行的頂部),這一切看起來都會更簡單。然后,您需要的只是 progressDone 標志,而不是為進度值的每次修改鎖定和列印。您可以在下面的演示中看到,它運行時會出現零執行緒清理器警告。確保調整列印間隔。此更改將運行時間從 ~10.7s 降低到 7s,盡管這只是一個指示 - 使用執行緒清理程式對程式進行計時是不合理的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/481808.html
下一篇:memcpy性能取決于目標向量
