To get a synchonized movement you simply send a step pulse to each stepper at (almost) the same time. Like:
for ( ; ; ) {
set_x_step_high();
set_y_step_high();
delay_microseconds(2); // or do some calculations
set_x_step_low();
set_y_step_low();
delay_milliseconds(5);
}
Synchonizing unconditionally always gives you 45 deg moves, of course. To deal with non-45 deg moves, the Bresenham algorithm is used. Originally written for pixel rendering, it applies to stepper motors, too, if you think of a step as being a pixel.
You can find a pretty straightforward real-world implementation of the above in Teacup firmware, file dda.c. Stepping is done in dda_step(), speed calculations are done in dda_start(), acceleration calculations and endstop handling in dda_clock().