Threads getting blocked in Jackson's SerializerCache - multithreading

I was load-testing my Spring Boot 1.3.5 application when I came across an odd behaviour. Upon increasing the number of requests to, say, 5000 requests/second, threads started to block on Jackson's SerializerCache. At first I thought it could be some misconfiguration on my side, so I created a fresh, minimal application:
#SpringBootApplication
public class DojoRestApplication {
public static void main(String[] args) {
SpringApplication.run(DojoRestApplication.class, args);
}
#RestController
public static final class StatusController {
#RequestMapping(method = GET, path = "/status", produces = "application/json")
public ResponseEntity<ApplicationStatus> get() {
final ApplicationStatus result = new ApplicationStatus();
result.setTimestamp(Instant.now());
result.setVersion("1.0.0");
return ResponseEntity.ok(result);
}
}
public static final class ApplicationStatus {
private Instant timestamp;
private String version;
public Instant getTimestamp() {
return timestamp;
}
public String getVersion() {
return version;
}
public void setTimestamp(Instant timestamp) {
this.timestamp = timestamp;
}
public void setVersion(String version) {
this.version = version;
}
}
}
Upon throwing a bunch of simultaneous requests at the /status endpoint here's what JProfiler tells me:
I took a thread dump and almost all the threads are stuck at this:
com.fasterxml.jackson.databind.ser.SerializerCache.untypedValueSerializer(java.lang.Class) (line: 84)
com.fasterxml.jackson.databind.SerializerProvider._findExplicitUntypedSerializer(java.lang.Class) (line: 1124)
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.hasSerializerFor(java.lang.Class, java.util.concurrent.atomic.AtomicReference) (line: 422)
com.fasterxml.jackson.databind.ObjectMapper.canSerialize(java.lang.Class, java.util.concurrent.atomic.AtomicReference)
org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.canWrite(java.lang.Class, org.springframework.http.MediaType) (line: 178)
org.springframework.http.converter.AbstractGenericHttpMessageConverter.canWrite(java.lang.reflect.Type, java.lang.Class, org.springframework.http.MediaType)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(java.lang.Object, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse) (line: 215)
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(java.lang.Object, org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest) (line: 183)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(java.lang.Object, org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest) (line: 81)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(org.springframework.web.context.request.ServletWebRequest, org.springframework.web.method.support.ModelAndViewContainer, java.lang.Object[ ]) (line: 126)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.web.method.HandlerMethod) (line: 832)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.web.method.HandlerMethod) (line: 743)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
org.springframework.web.servlet.DispatcherServlet.doDispatch(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 961)
org.springframework.web.servlet.DispatcherServlet.doService(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 895)
org.springframework.web.servlet.FrameworkServlet.processRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 967)
org.springframework.web.servlet.FrameworkServlet.doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 858)
javax.servlet.http.HttpServlet.service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 622)
org.springframework.web.servlet.FrameworkServlet.service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) (line: 843)
javax.servlet.http.HttpServlet.service(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 729)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 292)
org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207)
org.apache.tomcat.websocket.server.WsFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 52)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240)
org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207)
org.springframework.web.filter.RequestContextFilter.doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) (line: 99)
org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 107)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240)
org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207)
org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) (line: 87)
org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 107)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240)
org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) (line: 77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 107)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240)
org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) (line: 121)
org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) (line: 107)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 240)
org.apache.catalina.core.ApplicationFilterChain.doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse) (line: 207)
org.apache.catalina.core.StandardWrapperValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 212)
org.apache.catalina.core.StandardContextValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 106)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 502)
org.apache.catalina.core.StandardHostValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 141)
org.apache.catalina.valves.ErrorReportValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 79)
org.apache.catalina.core.StandardEngineValve.invoke(org.apache.catalina.connector.Request, org.apache.catalina.connector.Response) (line: 88)
org.apache.catalina.connector.CoyoteAdapter.service(org.apache.coyote.Request, org.apache.coyote.Response) (line: 522)
org.apache.coyote.http11.AbstractHttp11Processor.process(org.apache.tomcat.util.net.SocketWrapper) (line: 1095)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(org.apache.tomcat.util.net.SocketWrapper, org.apache.tomcat.util.net.SocketStatus) (line: 672)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun() (line: 1502)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run() (line: 1458)
java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) (line: 1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run() (line: 617)
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run() (line: 61)
java.lang.Thread.run() (line: 745)
It seems strange to me that this is happening, as it looks like Jackson is creating a serializer every single request or something. What can be causing this behaviour? Is this on Jackson's or Spring Boot's side (or mine, though I didn't really change any config)? The Jackson version in use is 2.6.6 (Spring Boot 1.3.5's default).

Jackson is not creating a new serializer for each request; that specific line is small synchronization block for simple get lookup from a HashMap. It would seem odd to have that synchronization to last anywhere long enough for threads to contest it. So I wonder if this might be an artifact of profiling.
However: that method itself should not be called much after ObjectMapper gets called by first thread(s); after initial lookup succeeds, serializer is added into shared map, but further SerializerProviders that get constructed should get a read-only copy with newly bound serializer. So it is puzzling why it would be accessed continuously.
Perhaps you could file an issue at jackson-databind issue tracker? 2.6 is new enough that the behavior probably still exists in 2.7 as well.

Related

JavaFX reset graphics Context after scaling a canvas

I'm trying to make a chart without using any 3rd party libs. I've a zoom feature which scales the Canvas correctly, but now I need to redraw everything inside the canvas once again.
But when I do scaling the GrapphicsContext also scales and blots. I want to readjust the blotting and show points in normal drawing once zoomed. How can I achieve this?
Here is simple snippet that I'm redrawing:
private void redrawImage(Canvas canvas, int scale) {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
gc.scale(scale, scale);
gc.setStroke(Color.RED);
gc.setLineWidth(2);
gc.strokeRect(0, 0, canvas.getWidth(), canvas.getHeight());
gc.setStroke(Color.GREEN);
gc.strokeLine(0, 0, canvas.getWidth(), canvas.getHeight());
gc.strokeLine(0, canvas.getHeight(), canvas.getWidth(), 0);
gc.setStroke(Color.BLUE);
gc.strokeText("TEXT", 50, 50);
}
Even I remove gc.scale(X,Y) I still see the blotted points or text, I want the scale to be always 1, but I should also zoom or scale simultaneously.
What I want to achieve is like the GoogleMaps overlaying, you see the objects when zoomed in or out are recalibrated and adjusted to a viewable scale. This is exactly what I want to achieve.
I don't know if I understand you correct.
Your redrawImage method should get an double and not an int value for the scale. Even if you try to scale to 1.9 the cast from double to int will bring it down to 1.
I've made a little example:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.FlowPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage primaryStage) {
Canvas canvas = new Canvas(100, 100);
Canvas canvas2 = new Canvas(100, 100);
FlowPane root = new FlowPane();
root.getChildren().addAll(canvas, canvas2);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
redrawImage(canvas, 0.5);
redrawImage(canvas2, 1);
}
private void redrawImage(Canvas canvas, double scale) {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
gc.scale(scale, scale);
gc.setStroke(Color.RED);
gc.setLineWidth(2);
gc.strokeRect(0, 0, canvas.getWidth(), canvas.getHeight());
gc.setStroke(Color.GREEN);
gc.strokeLine(0, 0, canvas.getWidth(), canvas.getHeight());
gc.strokeLine(0, canvas.getHeight(), canvas.getWidth(), 0);
gc.setStroke(Color.BLUE);
gc.strokeText("TEXT", 50, 50);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
With the following result:

Periodically refresh data

I want to display data periodically but I get error when I try to display the data.
Timeline fiveSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(3), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
GridPane gp = new GridPane();
gp.setPadding(new Insets(10, 10, 10, 10));
gp.setHgap(20);
gp.setVgap(10);
//gp.setGridLinesVisible(true);
gp.add(new Label("Operating System Name"), 0, 0);
gp.add(new Label(System.getProperty("os.name")), 1, 0);
gp.add(new Label("Operating System Version"), 0, 1);
gp.add(new Label(System.getProperty("os.version")), 1, 1);
gp.add(new Label("System Architecture"), 0, 2);
gp.add(new Label(System.getProperty("os.arch")), 1, 2);
gp.add(new Label("Total Memory"), 0, 3);
String memStrLong = Long.toString(Runtime.getRuntime().totalMemory());
gp.add(new Label(memStrLong), 1, 3);
gp.add(new Label("Used Memory"), 0, 4);
String fStrLong = Long.toString(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
gp.add(new Label(fStrLong), 1, 4);
gp.add(new Label("Java Version"), 0, 5);
gp.add(new Label(System.getProperty("java.version")), 1, 5);
gp.add(new Label("Number of Processors"), 0, 6);
String pStrLong = Long.toString(Runtime.getRuntime().availableProcessors());
gp.add(new Label(pStrLong), 1, 6);
gp.add(new Label("Maximum available Memory"), 0, 7);
String amStrLong = Long.toString(Runtime.getRuntime().maxMemory());
gp.add(new Label(amStrLong), 1, 7);
}
}));
fiveSecondsWonder.setCycleCount(Timeline.INDEFINITE);
fiveSecondsWonder.play();
Vbox.getChildren().add(gp);
Can you help me to implement properly this example, please?
EDIT: Second test:
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
}
});
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
final GridPane gp = new GridPane();
#Override
public void run() {
gp.getChildren().clear();
gp.setPadding(new Insets(10, 10, 10, 10));
gp.setHgap(20);
gp.setVgap(10);
//gp.setGridLinesVisible(true);
gp.add(new Label("Operating System Name"), 0, 0);
gp.add(new Label(System.getProperty("os.name")), 1, 0);
gp.add(new Label("Operating System Version"), 0, 1);
gp.add(new Label(System.getProperty("os.version")), 1, 1);
gp.add(new Label("System Architecture"), 0, 2);
gp.add(new Label(System.getProperty("os.arch")), 1, 2);
gp.add(new Label("Total Memory"), 0, 3);
String memStrLong = Long.toString(Runtime.getRuntime().totalMemory());
gp.add(new Label(memStrLong), 1, 3);
gp.add(new Label("Used Memory"), 0, 4);
String fStrLong = Long.toString(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
gp.add(new Label(fStrLong), 1, 4);
gp.add(new Label("Java Version"), 0, 5);
gp.add(new Label(System.getProperty("java.version")), 1, 5);
gp.add(new Label("Number of Processors"), 0, 6);
String pStrLong = Long.toString(Runtime.getRuntime().availableProcessors());
gp.add(new Label(pStrLong), 1, 6);
gp.add(new Label("Maximum available Memory"), 0, 7);
String amStrLong = Long.toString(Runtime.getRuntime().maxMemory());
gp.add(new Label(amStrLong), 1, 7);
vb.getChildren().add(gp);
}
}, 0, 1, TimeUnit.SECONDS);
I also tested this but with the data is not updated.
public class Sandbox extends Application {
private final StringProperty totalMemoryProperty = new SimpleStringProperty();
private final StringProperty usedMemoryProperty = new SimpleStringProperty();
private final StringProperty maxMemoryProperty = new SimpleStringProperty();
public static void main(final String[] args) throws Exception {
launch(args);
}
#Override
public void start(final Stage stage) throws Exception {
final GridPane gp = new GridPane();
gp.setPadding(new Insets(10, 10, 10, 10));
gp.setHgap(20);
gp.setVgap(10);
gp.add(new Label("Operating System Name"), 0, 0);
gp.add(new Label(System.getProperty("os.name")), 1, 0);
gp.add(new Label("Operating System Version"), 0, 1);
gp.add(new Label(System.getProperty("os.version")), 1, 1);
gp.add(new Label("System Architecture"), 0, 2);
gp.add(new Label(System.getProperty("os.arch")), 1, 2);
gp.add(new Label("Java Version"), 0, 5);
gp.add(new Label(System.getProperty("java.version")), 1, 5);
gp.add(new Label("Number of Processors"), 0, 6);
String pStrLong = Long.toString(Runtime.getRuntime().availableProcessors());
gp.add(new Label(pStrLong), 1, 6);
gp.add(new Label("Total Memory"), 0, 3);
gp.add(new Label("Used Memory"), 0, 4);
gp.add(new Label("Maximum available Memory"), 0, 7);
final Label totalMemoryLabel = new Label();
totalMemoryLabel.textProperty().bind(totalMemoryProperty);
gp.add(totalMemoryLabel, 1, 3);
final Label usedMemoryLabel = new Label();
usedMemoryLabel.textProperty().bind(usedMemoryProperty);
gp.add(usedMemoryLabel, 1, 4);
final Label maxMemoryLabel = new Label();
maxMemoryLabel.textProperty().bind(maxMemoryProperty);
gp.add(maxMemoryLabel, 1, 7);
final VBox rootNode = new VBox();
rootNode.getChildren().add(gp);
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
}
});
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
final Runnable runnable = new Runnable() {
#Override
public void run() {
String memStrLong = Long.toString(Runtime.getRuntime().totalMemory());
totalMemoryProperty.setValue(memStrLong);
String fStrLong = Long.toString(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
usedMemoryProperty.setValue(fStrLong);
String amStrLong = Long.toString(Runtime.getRuntime().maxMemory());
maxMemoryProperty.setValue(amStrLong);
}
};
Platform.runLater(runnable);
}
}, 0, 1, TimeUnit.SECONDS);
final Scene scene = new Scene(rootNode, 1024, 768);
stage.setScene(scene);
stage.show();
}
}
I made your code work with databinding, use Platform.runLater() to go back to the GUI thread to update javafx components.
If you want to use ScheduledService here is a basic example:
public class Sandbox extends Application {
public static void main(final String[] args) throws Exception {
launch(args);
}
class MyService extends ScheduledService<List<String>> {
#Override
protected Task<List<String>> createTask() {
final Task<List<String>> voidTask = new Task<List<String>>() {
#Override
protected List<String> call() throws Exception {
List<String> results = new ArrayList<>();
final String memStrLong = Long.toString(Runtime.getRuntime().totalMemory());
results.add(memStrLong);
final String fStrLong = Long.toString(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
results.add(fStrLong);
final String amStrLong = Long.toString(Runtime.getRuntime().maxMemory());
results.add(amStrLong);
return results;
}
};
return voidTask;
}
}
#Override
public void start(final Stage stage) throws Exception {
final GridPane gp = new GridPane();
gp.setPadding(new Insets(10, 10, 10, 10));
gp.setHgap(20);
gp.setVgap(10);
gp.add(new Label("Operating System Name"), 0, 0);
gp.add(new Label(System.getProperty("os.name")), 1, 0);
gp.add(new Label("Operating System Version"), 0, 1);
gp.add(new Label(System.getProperty("os.version")), 1, 1);
gp.add(new Label("System Architecture"), 0, 2);
gp.add(new Label(System.getProperty("os.arch")), 1, 2);
gp.add(new Label("Java Version"), 0, 5);
gp.add(new Label(System.getProperty("java.version")), 1, 5);
gp.add(new Label("Number of Processors"), 0, 6);
final String pStrLong = Long.toString(Runtime.getRuntime().availableProcessors());
gp.add(new Label(pStrLong), 1, 6);
gp.add(new Label("Total Memory"), 0, 3);
gp.add(new Label("Used Memory"), 0, 4);
gp.add(new Label("Maximum available Memory"), 0, 7);
final Label totalMemoryLabel = new Label();
gp.add(totalMemoryLabel, 1, 3);
final Label usedMemoryLabel = new Label();
gp.add(usedMemoryLabel, 1, 4);
final Label maxMemoryLabel = new Label();
gp.add(maxMemoryLabel, 1, 7);
final VBox rootNode = new VBox();
rootNode.getChildren().add(gp);
final MyService service = new MyService();
service.setDelay(new Duration(300));
service.setPeriod(new Duration(1000));
service.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(final WorkerStateEvent workerStateEvent) {
List<String> results = (List<String>) workerStateEvent.getSource().getValue();
totalMemoryLabel.setText(results.get(0));
usedMemoryLabel.setText(results.get(1));
maxMemoryLabel.setText(results.get(2));
}
});
service.start();
final Scene scene = new Scene(rootNode, 1024, 768);
stage.setScene(scene);
stage.show();
}
}

MemDC in OnPaint()-function

My OnPaint() function calls several other drawing functions.
void CGraph::OnPaint ()
{
CPaintDC dc(this);
// CMemDC DC(&dc);
dc.SetViewportOrg (0, 400);
dc.SetMapMode(MM_ISOTROPIC);
dc.SetWindowExt(1000, 800);
dc.SetViewportExt(1000, -800);
ProcessData ();
DrawCoordinateSystem (&dc);
DrawGrid (&dc);
DrawGraph (&dc);
}
Example of DrawCoordianteSystem:
void CGraph::DrawCoordinateSystem (CDC* pDC)
{
CPen PenBlack (PS_SOLID, 1, RGB(0, 0, 0));
pDC->SelectObject (PenBlack);
// Rectangle round the system
pDC->Rectangle (0, -400, 1000, 400);
// Horizontal axis
pDC->MoveTo (0, 0);
pDC->LineTo (1000, 0);
pDC->SetTextColor (RGB(0,0,0));
pDC->SetBkColor (RGB(240, 240, 240));
pDC->TextOut (1001, 0, L"0");
// Vertical axis
pDC->MoveTo (0, -400);
pDC->LineTo (0, 400);
}
I now want to avoid flickering with CMemDC. However, i can't get it to work right. Can somebody show me how to implement CMemDC right?
Thanks
You need to load the memory DC with a bitmap to then BitBlt to the screen DC.
Try something like:
CDC dcMem;
CBitmap bitmap;
dcMem.CreateCompatibleDC( pDC );
bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height())
CBitmap* pOldBitmap = dcMem.SelectObject(&bitmap);
... DO ALL YOUR DRAWING TO dcMem ...
pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY);
dcMem.SelectObject(pOldBitmap)
To avoid flickers you should draw everything on CMemDC and BitBlt it to the real DC.
Secondly add windows message handler for WM_ERASEBKGND message and change the code to
BOOL CGraph::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
}

textFieldShouldReturn is not working in ipad

I am creating an application on IPad. I use a text field with default return key to write message.After writing a message I press return key..Then the keyboard dissappeared, but the method - (BOOL)textFieldShouldReturn:(UITextField *)textField {} does NOT get called. I have some code within the textFieldShouldReturn function...
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
if(cPageNavType == CUTSOM_NAV_BAR){
mToolbar.frame = CGRectMake(0, 438, 320, 44);
mTableView.frame = CGRectMake(0, 40, 340, 400);
}else {
mTableView.frame = CGRectMake(0, 0, 340, 480-44-18-28);
mToolbar.frame = CGRectMake(0, 480-44-18-28, 320, 44);
}
[UIView commitAnimations];
//[self postMessage:nil];
return YES;
}
so what can I do? Thanks in advance
Things to check
Add <UITextFieldDelegate> ,make your class receiver of delegate
OfCourse add delegate method(put break points)
Connect the textfield outlets (delegates and referencing outlets if any)

comparison GCD vs. performSelectorInBackground: dispatch_async not in background

Grand Central Dispatch is great and reduces the amount of code but why I cannot run something on a background thread?
I have made a sample application to show what I mean (none of the commented work):
- (IBAction)performSel {
[self performSelectorInBackground:#selector(doStuff) withObject:nil];
[NSThread sleepForTimeInterval:3];
[[self.view.subviews lastObject] removeFromSuperview];
}
- (IBAction)gcd {
dispatch_async(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
//dispatch_sync(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
//dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
//dispatch_async(dispatch_get_main_queue(), ^(void) {
//dispatch_sync(dispatch_get_main_queue(), ^(void) {
[self doStuff]; // only for readability, will move the code on success
});
[NSThread sleepForTimeInterval:3];
[[self.view.subviews lastObject] removeFromSuperview];
}
- (void)doStuff {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
UIView *abortingView = [[UIView alloc]initWithFrame: self.view.bounds];
abortingView.backgroundColor = [UIColor whiteColor];
abortingView.alpha = 0.7;
[self.view insertSubview:abortingView atIndex:10];
[abortingView release];
[pool drain];
}
the [NSThread sleepForTimeInterval:3]; is to simulate a default UI functionality. For example if someone is switching from one navigation view to another.
Simply copy the code in a new view based application, create two buttons and connect them.
UIKit classes should be used only from an application’s main thread. (From iOS4, drawing to a graphics context is thread-safe.) You can't use UIKit stuff in a background thread.
Thus, you can only use dispatch_async(dispatch_get_main_queue(), block) in this situation.
dispatch_async(dispatch_get_main_queue(), ^(void) {
It will invoke the block on the main thread in the runloop of the main thread.
dispatch_async(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
It will invoke the block in a background thread. You can't use it because you want to use UIKit in the block. And be careful dispatch_async(dispatch_queue_create(, it might cause memory leak, you have to release the serial queue that is created by dispatch_queue_create.
dispatch_sync(dispatch_queue_create("myGCDqueue", NULL), ^(void) {
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
dispatch_sync waits until the block is done.
dispatch_sync(dispatch_get_main_queue(), ^(void) {
It causes DEADLOCK.

Resources