Qt. How correctly print data from QThread object? - multithreading

I have QList which contains inhereted from QThread objects. These objects in run() method do some work in cycle with different periodicity(I use QThread::sleep) and results save in private fields.
Question
How correct print result in QTableView or QTableWidget?
my idea - create thread that will print in QTableWidget result in infinity cycle, but I guess that this idea is terrible...
//httpgettask.h
//Task inherit from QThread
class HttpGetTask : public Task
{
public:
HttpGetTask(const QString &, const int &, const int &);
HttpGetTask(const QUrl &, const int &, const int &);
void run();
};
//httpgettask.cpp
HttpGetTask::HttpGetTask(const QUrl &url, const int &period, const int &errLimit) :
Task(url, period, errLimit, "HTTP GET")
{
}
HttpGetTask::HttpGetTask(const QString &url, const int &period, const int &errLimit) :
Task(url, period, errLimit, "HTTP GET")
{
}
void HttpGetTask::run()
{
TestConn conn(url);
Response res;
QString msg;
int errCount = 0;
while (!stopThread)
{
msg = "";
res = conn.get();
if (!res.isSuccess())
{
if (++errCount == errLimit) {
msg = QString("ERROR!! %1 ERROR").arg(errLimit);
++errors;
errCount = 0;
}
}
msg = QString("%1 %2 %3 %4").arg(QDateTime::currentDateTime().toString(datePattern),
msg,
"HTTP_GET",
res.getMessage());
writeResultFile(msg);
++checkCount;
QThread::sleep(period);
}
}

I solved the problem. Just create QTimer and update QTableWidget in timer slot

Related

How to create a structure initialized with default values?

How to create a structure that already has default values?
Somehow like this:
struct First {
int data = 4;
int pos = 5;
}
void main () {
var a = First ();
assert(a.data == 4);
}
The response from AlThomas:
"Structs in Vala can have initializers (similar to a constructor for a class) and methods. So what I can extract from your second pastebin you could write that as:"
struct First {
int data;
int pos;
public First (int[] mass) {
data= 5;
pos = mass.length;
}
public int sas () {
return data + pos;
}
}
void main () {
int[] a = {1,3,0,1,2,3,2,1};
var b = First (a);
print (#"$(b.sas ())\n");
}

How to implement keyboard handler cefSharp for shortcut keys

I've building a windows app for browsing web pages using cefSharp.
I need to implement some short cut keys into that application, can any one tell me how can i achieve this functionality.
Ex.
ctrl + tab = move to next tab
I'm able to track if user presses any single key, but unable to track multi key pressing.
IKeyboardHandler
public class KeyboardHandler : IKeyboardHandler
{
public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
{
bool result = false;
Debug.WriteLine(String.Format("OnKeyEvent: KeyType: {0} 0x{1:X} Modifiers: {2}", type, windowsKeyCode, modifiers));
// TODO: Handle MessageNeeded cases here somehow.
return result;
}
public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
{
const int WM_SYSKEYDOWN = 0x104;
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
const int WM_SYSKEYUP = 0x105;
const int WM_CHAR = 0x102;
const int WM_SYSCHAR = 0x106;
const int VK_TAB = 0x9;
bool result = false;
isKeyboardShortcut = false;
// Don't deal with TABs by default:
// TODO: Are there any additional ones we need to be careful of?
// i.e. Escape, Return, etc...?
if (windowsKeyCode == VK_TAB)
{
return result;
}
Control control = browserControl as Control;
int msgType = 0;
switch (type)
{
case KeyType.RawKeyDown:
if (isSystemKey)
{
msgType = WM_SYSKEYDOWN;
}
else
{
msgType = WM_KEYDOWN;
}
break;
case KeyType.KeyUp:
if (isSystemKey)
{
msgType = WM_SYSKEYUP;
}
else
{
msgType = WM_KEYUP;
}
break;
case KeyType.Char:
if (isSystemKey)
{
msgType = WM_SYSCHAR;
}
else
{
msgType = WM_CHAR;
}
break;
default:
Trace.Assert(false);
break;
}
// We have to adapt from CEF's UI thread message loop to our fronting WinForm control here.
// So, we have to make some calls that Application.Run usually ends up handling for us:
PreProcessControlState state = PreProcessControlState.MessageNotNeeded;
// We can't use BeginInvoke here, because we need the results for the return value
// and isKeyboardShortcut. In theory this shouldn't deadlock, because
// atm this is the only synchronous operation between the two threads.
control.Invoke(new Action(() =>
{
Message msg = new Message() { HWnd = control.Handle, Msg = msgType, WParam = new IntPtr(windowsKeyCode), LParam = new IntPtr(nativeKeyCode) };
// First comes Application.AddMessageFilter related processing:
// 99.9% of the time in WinForms this doesn't do anything interesting.
bool processed = Application.FilterMessage(ref msg);
if (processed)
{
state = PreProcessControlState.MessageProcessed;
}
else
{
// Next we see if our control (or one of its parents)
// wants first crack at the message via several possible Control methods.
// This includes things like Mnemonics/Accelerators/Menu Shortcuts/etc...
state = control.PreProcessControlMessage(ref msg);
}
}));
if (state == PreProcessControlState.MessageNeeded)
{
// TODO: Determine how to track MessageNeeded for OnKeyEvent.
isKeyboardShortcut = true;
}
else if (state == PreProcessControlState.MessageProcessed)
{
// Most of the interesting cases get processed by PreProcessControlMessage.
result = true;
}
Debug.WriteLine(String.Format("OnPreKeyEvent: KeyType: {0} 0x{1:X} Modifiers: {2}", type, windowsKeyCode, modifiers));
Debug.WriteLine(String.Format("OnPreKeyEvent PreProcessControlState: {0}", state));
return result;
}
Finally got an alternative to implement shortcut functionality without implementing IKeyboardHandler.
Here i used Global Keyboard Hook to implement this.
GlobalKeyboardHook
public class GlobalKeyboardHook
{
#region Variables and dll import
#region For key capturing
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref keyBoardHookStruct lParam);
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, LLKeyboardHook callback, IntPtr hInstance, uint theardID);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public delegate int LLKeyboardHook(int Code, int wParam, ref keyBoardHookStruct lParam);
public struct keyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
const int WH_KEYBOARD_LL = 13;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
const int WM_SYSKEYDOWN = 0x0104;
const int WM_SYSKEYUP = 0x0105;
LLKeyboardHook llkh;
public List<Keys> HookedKeys = new List<Keys>();
IntPtr Hook = IntPtr.Zero;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
#endregion
#region For modifier capturing
/// <summary>
/// Gets the state of modifier keys for a given keycode.
/// </summary>
/// <param name="keyCode">The keyCode</param>
/// <returns></returns>
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
public static extern short GetKeyState(int keyCode);
//Modifier key vkCode constants
private const int VK_SHIFT = 0x10;
private const int VK_CONTROL = 0x11;
private const int VK_MENU = 0x12;
private const int VK_CAPITAL = 0x14;
#endregion
#endregion
#region Constructor
// This is the Constructor. This is the code that runs every time you create a new GlobalKeyboardHook object
public GlobalKeyboardHook()
{
llkh = new LLKeyboardHook(HookProc);
// This starts the hook. You can leave this as comment and you have to start it manually
// Or delete the comment mark and your hook will start automatically when your program starts (because a new GlobalKeyboardHook object is created)
// That's why there are duplicates, because you start it twice! I'm sorry, I haven't noticed this...
// hook(); <-- Choose!
}
~GlobalKeyboardHook()
{ unhook(); }
#endregion
#region Functions and implementation
/// <summary>
/// Hook (Start listening keybord events)
/// </summary>
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
Hook = SetWindowsHookEx(WH_KEYBOARD_LL, llkh, hInstance, 0);
}
/// <summary>
/// Unhook (Stop listening keybord events)
/// </summary>
public void unhook()
{
UnhookWindowsHookEx(Hook);
}
/// <summary>
/// Pass key into event
/// </summary>
/// <param name="Code">Key code</param>
/// <param name="wParam">int event type (keydown/keyup)</param>
/// <param name="lParam">keyBoardHookStruct enum for detecting key</param>
/// <returns>next hook call</returns>
public int HookProc(int Code, int wParam, ref keyBoardHookStruct lParam)
{
if (Code >= 0)
{
Keys key = (Keys)lParam.vkCode;
if (HookedKeys.Contains(key))
{
//Get modifiers
key = AddModifiers(key);
KeyEventArgs kArg = new KeyEventArgs(key);
if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null))
{
KeyDown(this, kArg);
}
else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null))
{
KeyUp(this, kArg);
}
if (kArg.Handled)
return 1;
}
}
return CallNextHookEx(Hook, Code, wParam, ref lParam);
}
/// <summary>
/// Checks whether Alt, Shift, Control or CapsLock
/// is pressed at the same time as the hooked key.
/// Modifies the keyCode to include the pressed keys.
/// </summary>
private Keys AddModifiers(Keys key)
{
//CapsLock
if ((GetKeyState(VK_CAPITAL) & 0x0001) != 0) key = key | Keys.CapsLock;
//Shift
if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) key = key | Keys.Shift;
//Ctrl
if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) key = key | Keys.Control;
//Alt
if ((GetKeyState(VK_MENU) & 0x8000) != 0) key = key | Keys.Alt;
return key;
}
#endregion
}
Start hook
To start hook add below code to form load or application start
//Start listening keybord events
gHook = new GlobalKeyboardHook();
gHook.KeyDown += new KeyEventHandler(gHook_KeyDown);
foreach (Keys key in Enum.GetValues(typeof(Keys)))
{
gHook.HookedKeys.Add(key);
}
gHook.hook();
Stop hook
Add this code on application exit(form closing event)
//Stop listening keybord events
gHook.unhook();
Handel key down event for shortcut implementation
public void gHook_KeyDown(object sender, KeyEventArgs e)
{
if (this.ContainsFocus)
{
if (e.KeyData.ToString().ToUpper().IndexOf("ALT".ToUpper()) >= 0
&& e.KeyValue == 66)//B = 66
{
//ALT + B
new Thread(() =>
{
// execute this on the gui thread. (winforms)
this.Invoke(new Action(delegate
{
tosBrowserBtnBack_Click(this, new EventArgs());
}));
}).Start();
}
else if (e.KeyData.ToString().ToUpper().IndexOf("ALT".ToUpper()) >= 0
&& e.KeyValue == 70)//F = 70
{
//ALT + F
new Thread(() =>
{
// execute this on the gui thread. (winforms)
this.Invoke(new Action(delegate
{
tosBrowserBtnFor_Click(this, new EventArgs());
}));
}).Start();
}
}
Global hook works for every keystroke whether your application has focus or not, so here I've used this.ContainsFocus to check current form has focus or not, if has then handle shortcut events. If you need to implementation shortcut on hole application then you need to check if application has focus or not.
For that you need to create a new class
ApplicationFocus
public class ApplicationFocus
{
/// <summary>Returns true if the current application has focus, false otherwise</summary>
public static bool ApplicationIsActivated()
{
var activatedHandle = GetForegroundWindow();
if (activatedHandle == IntPtr.Zero)
{
return false; // No window is currently activated
}
var procId = Process.GetCurrentProcess().Id;
int activeProcId;
GetWindowThreadProcessId(activatedHandle, out activeProcId);
return activeProcId == procId;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
}
Then replace if (this.ContainsFocus) with ApplicationFocus.ApplicationIsActivated() in gHook_KeyDown event.
This is worked for me.

Worker is not finished while sending message to intermediate worker

I am using "programming in D" to learn about D language. I wrote a simple program that spawns a worker and sends it a number to receive its square as a string. The worker 1 gets the number squares it and sends to worker 2 (a different function) to get casted as string which is returned to the worker 1 and thus it returns it to the main function call. I can write the whole thing in a single thread. I wrote it to understand about workers better. I used receive to get the worker 1 act as per the input. The program is as follows
import std.stdio;
import std.concurrency;
import std.conv;
import core.thread;
void main() {
foreach (int num; 1..100) {
auto square_tid = spawn(&square);
square_tid.send(num);
auto square = receiveOnly!string();
writeln(square);
}
}
void square() {
static i = 0;
receive (
(int num) {
auto square = num * num;
writeln("sqaure : Comes in with " , num , " for " , ++i , " time");
auto stringWorker = spawn(&stringConverter);
stringWorker.send(thisTid, square, ownerTid);
},
(Tid tid, string str) {
writeln("comes in string");
send(tid, "hello");
});
}
void stringConverter() {
static i = 0;
auto params = receiveOnly!(Tid, int, Tid)();
auto stringified = to!string(params[1]); // Stringify the square
writeln("string : Comes in with " , params[1], " for " , ++i , " time");
params[0].send(params[2], stringified); // params[0] - square function tid, params[2] - main function tid
}
I can receive the main function tid and directly send the string back. But when I return to the worker 1 it gets struck and doesn't proceed further. How can I make a thread to receive input from master thread and also from the slave thread. Another few questions about threads :
If I want to send -1 as the data to my worker without exiting it. How can I do it?
Is it ok to use a single worker for the whole process or I can use multiple workers as I did in the foreach loop?
The book uses the following code. Why does it have the value >= 0 as its obvious in the code.
import std.stdio;
import std.concurrency;
import std.conv;
void main() {
Tid worker = spawn(&workerFunc);
foreach (value; 1 .. 5) {
worker.send(value);
double result = receiveOnly!double();
writefln("sent: %s, received: %s", value, result);
}
/* Sending a negative value to the worker so that it
* terminates. */
worker.send(-1);
}
void workerFunc() {
int value = 0;
while (value >= 0) {
value = receiveOnly!int();
double result = to!double(value) / 5;
ownerTid.send(result);
}
}
Correct me if I am wrong in any of the terminologies.
For this kind of task is better to use std.parallelism
import std.stdio;
import std.parallelism;
void main() {
auto squares = new long[100];
foreach(i, ref elem; parallel(squares)) {
elem = i * i;
}
writeln(squares);
}
And there is no problem with sending -1 to worker thread, it will not exit thread only when it is explicitly ask.
And here is a modified version of your attempt:
import std.stdio;
import std.concurrency;
import std.conv;
void main() {
foreach (int num; 1..100) {
auto square_tid = spawn(&square);
square_tid.send(num);
auto square = receiveOnly!string();
writeln(square);
}
}
void square() {
static shared i = 0;
receive (
(int num) {
int square = num * num;
writeln("sqaure : Comes in with " , num , " for " , ++i , " time");
auto stringWorker = spawn(&stringConverter);
stringWorker.send(thisTid, square, ownerTid);
receive ((Tid tid, string str) { writeln("comes in string"); send(tid, "hello");});
});
}
void stringConverter() {
static shared i = 0;
auto params = receiveOnly!(Tid, int, Tid)();
auto stringified = to!string(params[1]); // Stringify the square
writeln("string : Comes in with " , params[1], " for " , ++i , " time");
params[0].send(params[2], stringified); // params[0] - square function tid, params[2] - main function tid
}
UPDATE explanation
the square function in your code ends after receive. So it never try the next block with (Tid tid, string str) part. This is why I put it inside the first part of receive.
With each call of spawn you creating new thread. And because D use TLS by default the static keyword is useless in your example. Because in every new thread i would be 0. This is why I use shared keyword.
UPDATE 2
here is a version which could explain more how things works:
import std.stdio;
import std.concurrency;
import std.conv;
void main() {
foreach (int num; 1..100) {
auto square_tid = spawn(&square);
square_tid.send(num);
auto square = receiveOnly!string();
writeln(square);
}
}
void square() {
shared static i = 0;
bool end = false;
while(!end) receive (
(int num) {
auto square = num * num;
writeln("sqaure : Comes in with " , num , " for " , ++i , " time");
auto stringWorker = spawn(&stringConverter);
stringWorker.send(square);
},
(string str) {
writeln("comes in string");
ownerTid.send(str);
end = true;
});
}
void stringConverter() {
shared static i = 0;
auto params = receiveOnly!(int)();
auto stringified = to!string(params); // Stringify the square
writeln("string : Comes in with " , params, " for " , ++i , " time");
ownerTid.send(stringified); // params[0] - square function tid, params[2] - main function tid
}

Run RichTextBox on its own thread?

Background
I have a RichTextBox control I am using essentially like a console in my WinForms application. Currently my application-wide logger posts messages using delegates and one of the listeners is this RTB. The logger synchronously sends lots of short (less than 100 char) strings denoting event calls, status messages, operation results, etc.
Posting lots of these short messages to the RTB using BeginInvoke provides UI responsiveness until heavy parallel processing starts logging lots of messages and then the UI starts posting items out of order, or the text is far behind (hundreds of milliseconds). I know this because when the processing slows down or is stopped, the console keeps writing for some time afterwords.
My temporary solution was to invoke the UI synchronously and add a blocking collection buffer. Basically taking the many small items from the Logger and combining them in a stringbuilder to be posted in aggregate to the RTB. The buffer posts items as they come if the UI can keep up, but if the queue gets too high, then it aggregates them and then posts to the UI. The RTB is thus updated piece-meal and looks jumpy when lots of things are being logged.
Question
How can I run a RichTextBox control on its own UI thread to keep other buttons on the same Form responsive during frequent but small append operations? From research, I think I need to run an STA thread and call Application.Run() on it to put the RTB on its own thread, but the examples I found lacked substantive code samples and there don't seem to be any tutorials (perhaps because what I want to do is ill advised?). Also I wasn't sure if there where any pitfalls for a single Control being on its own thread relative to the rest of the Form. (ie. Any issues closing the main form or will the STA thread for the RTB just die with the form closing? Any special disposing? etc.)
This should demonstrate the issue once you add 3 Buttons and a RichTextBox to the form. What I essentially want to accomplish is factoring away the BufferedConsumer by having the RTB on its own thread. Most of this code was hacked out verbatim from my main application, so yes, it is ugly.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
// Fields
private int m_taskCounter;
private static CancellationTokenSource m_tokenSource;
private bool m_buffered = true;
private static readonly object m_syncObject = new object();
// Properties
public IMessageConsole Application_Console { get; private set; }
public BufferedConsumer<StringBuilder, string> Buffer { get; private set; }
public Form1()
{
InitializeComponent();
m_tokenSource = new CancellationTokenSource();
Application_Console = new RichTextBox_To_IMessageConsole(richTextBox1);
Buffer =
new BufferedConsumer<StringBuilder, string>(
p_name: "Console Buffer",
p_appendBuffer: (sb, s) => sb.Append(s),
p_postBuffer: (sb) => Application_Console.Append(sb));
button1.Text = "Start Producer";
button2.Text = "Stop All";
button3.Text = "Toggle Buffering";
button1.Click += (o, e) => StartProducerTask();
button2.Click += (o, e) => CancelAllProducers();
button3.Click += (o, e) => ToggleBufferedConsumer();
}
public void StartProducerTask()
{
var Token = m_tokenSource.Token;
Task
.Factory.StartNew(() =>
{
var ThreadID = Interlocked.Increment(ref m_taskCounter);
StringBuilder sb = new StringBuilder();
var Count = 0;
while (!Token.IsCancellationRequested)
{
Count++;
sb.Clear();
sb
.Append("ThreadID = ")
.Append(ThreadID.ToString("000"))
.Append(", Count = ")
.AppendLine(Count.ToString());
if (m_buffered)
Buffer
.AppendCollection(sb.ToString()); // ToString mimicks real world Logger passing strings and not stringbuilders
else
Application_Console.Append(sb);
Sleep.For(1000);
}
}, Token);
}
public static void CancelAllProducers()
{
lock (m_syncObject)
{
m_tokenSource.Cancel();
m_tokenSource = new CancellationTokenSource();
}
}
public void ToggleBufferedConsumer()
{
m_buffered = !m_buffered;
}
}
public interface IMessageConsole
{
// Methods
void Append(StringBuilder p_message);
}
// http://stackoverflow.com/a/5706085/1718702
public class RichTextBox_To_IMessageConsole : IMessageConsole
{
// Constants
private const int WM_USER = 0x400;
private const int WM_SETREDRAW = 0x000B;
private const int EM_GETEVENTMASK = WM_USER + 59;
private const int EM_SETEVENTMASK = WM_USER + 69;
private const int EM_GETSCROLLPOS = WM_USER + 221;
private const int EM_SETSCROLLPOS = WM_USER + 222;
//Imports
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);
// Fields
private RichTextBox m_richTextBox;
private bool m_attachToBottom;
private Point m_scrollPoint;
private bool m_painting;
private IntPtr m_eventMask;
private int m_suspendIndex = 0;
private int m_suspendLength = 0;
public RichTextBox_To_IMessageConsole(RichTextBox p_richTextBox)
{
m_richTextBox = p_richTextBox;
var h = m_richTextBox.Handle;
m_painting = true;
m_richTextBox.DoubleClick += RichTextBox_DoubleClick;
m_richTextBox.MouseWheel += RichTextBox_MouseWheel;
}
// Methods
public void SuspendPainting()
{
if (m_painting)
{
m_suspendIndex = m_richTextBox.SelectionStart;
m_suspendLength = m_richTextBox.SelectionLength;
SendMessage(m_richTextBox.Handle, EM_GETSCROLLPOS, 0, ref m_scrollPoint);
SendMessage(m_richTextBox.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
m_eventMask = SendMessage(m_richTextBox.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
m_painting = false;
}
}
public void ResumePainting()
{
if (!m_painting)
{
m_richTextBox.Select(m_suspendIndex, m_suspendLength);
SendMessage(m_richTextBox.Handle, EM_SETSCROLLPOS, 0, ref m_scrollPoint);
SendMessage(m_richTextBox.Handle, EM_SETEVENTMASK, 0, m_eventMask);
SendMessage(m_richTextBox.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
m_painting = true;
m_richTextBox.Invalidate();
}
}
public void Append(StringBuilder p_message)
{
var WatchDogTimer = Stopwatch.StartNew();
var MinimumRefreshRate = 2000;
m_richTextBox
.Invoke((Action)delegate
{
// Last resort cleanup
if (WatchDogTimer.ElapsedMilliseconds > MinimumRefreshRate)
{
// m_richTextBox.Clear(); // Real-world behaviour
// Sample App behaviour
Form1.CancelAllProducers();
}
// Stop Drawing to prevent flickering during append and
// allow Double-Click events to register properly
this.SuspendPainting();
m_richTextBox.SelectionStart = m_richTextBox.TextLength;
m_richTextBox.SelectedText = p_message.ToString();
// Cap out Max Lines and cut back down to improve responsiveness
if (m_richTextBox.Lines.Length > 4000)
{
var NewSet = new string[1000];
Array.Copy(m_richTextBox.Lines, 1000, NewSet, 0, 1000);
m_richTextBox.Lines = NewSet;
m_richTextBox.SelectionStart = m_richTextBox.TextLength;
m_richTextBox.SelectedText = "\r\n";
}
this.ResumePainting();
// AutoScroll down to display newest text
if (m_attachToBottom)
{
m_richTextBox.SelectionStart = m_richTextBox.Text.Length;
m_richTextBox.ScrollToCaret();
}
});
}
// Event Handler
void RichTextBox_DoubleClick(object sender, EventArgs e)
{
// Toggle
m_attachToBottom = !m_attachToBottom;
// Scroll to Bottom
if (m_attachToBottom)
{
m_richTextBox.SelectionStart = m_richTextBox.Text.Length;
m_richTextBox.ScrollToCaret();
}
}
void RichTextBox_MouseWheel(object sender, MouseEventArgs e)
{
m_attachToBottom = false;
}
}
public class BufferedConsumer<TBuffer, TItem> : IDisposable
where TBuffer : new()
{
// Fields
private bool m_disposed = false;
private Task m_consumer;
private string m_name;
private CancellationTokenSource m_tokenSource;
private AutoResetEvent m_flushSignal;
private BlockingCollection<TItem> m_queue;
// Constructor
public BufferedConsumer(string p_name, Action<TBuffer, TItem> p_appendBuffer, Action<TBuffer> p_postBuffer)
{
m_name = p_name;
m_queue = new BlockingCollection<TItem>();
m_tokenSource = new CancellationTokenSource();
var m_token = m_tokenSource.Token;
m_flushSignal = new AutoResetEvent(false);
m_token
.Register(() => { m_flushSignal.Set(); });
// Begin Consumer Task
m_consumer = Task.Factory.StartNew(() =>
{
//Handler
// .LogExceptions(ErrorResponse.SupressRethrow, () =>
// {
// Continuously consumes entries added to the collection, blocking-wait if empty until cancelled
while (!m_token.IsCancellationRequested)
{
// Block
m_flushSignal.WaitOne();
if (m_token.IsCancellationRequested && m_queue.Count == 0)
break;
// Consume all queued items
TBuffer PostBuffer = new TBuffer();
Console.WriteLine("Queue Count = " + m_queue.Count + ", Buffering...");
for (int i = 0; i < m_queue.Count; i++)
{
TItem Item;
m_queue.TryTake(out Item);
p_appendBuffer(PostBuffer, Item);
}
// Post Buffered Items
p_postBuffer(PostBuffer);
// Signal another Buffer loop if more items were Queued during post sequence
var QueueSize = m_queue.Count;
if (QueueSize > 0)
{
Console.WriteLine("Queue Count = " + QueueSize + ", Sleeping...");
m_flushSignal.Set();
if (QueueSize > 10 && QueueSize < 100)
Sleep.For(1000, m_token); //Allow Queue to build, reducing posting overhead if requests are very frequent
}
}
//});
}, m_token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool p_disposing)
{
if (!m_disposed)
{
m_disposed = true;
if (p_disposing)
{
// Release of Managed Resources
m_tokenSource.Cancel();
m_flushSignal.Set();
m_consumer.Wait();
}
// Release of Unmanaged Resources
}
}
// Methods
public void AppendCollection(TItem p_item)
{
m_queue.Add(p_item);
m_flushSignal.Set();
}
}
public static partial class Sleep
{
public static bool For(int p_milliseconds, CancellationToken p_cancelToken = default(CancellationToken))
{
//p_milliseconds
// .MustBeEqualOrAbove(0, "p_milliseconds");
// Exit immediate if cancelled
if (p_cancelToken != default(CancellationToken))
if (p_cancelToken.IsCancellationRequested)
return true;
var SleepTimer =
new AutoResetEvent(false);
// Cancellation Callback Action
if (p_cancelToken != default(CancellationToken))
p_cancelToken
.Register(() => SleepTimer.Set());
// Block on SleepTimer
var Canceled = SleepTimer.WaitOne(p_milliseconds);
return Canceled;
}
}
}
Posting answer as per the OP's request:
You can integrate my example of a Virtualized, High-Performance, Rich, highly customizable WPF log Viewer in your existing winforms application by using the ElementHost
Full source code in the link above

Trying to handle thread pool in a class

I'm trying to handle thread pool in a class.
below is my code.
#include <Windows.h>
class ClassA
{
public : // user API
ClassA()
{
}
~ClassA()
{
}
public : //my muiti-thread func
void init()
{
//*************************************
// multithread Initialization
//*************************************
pool = NULL;
cleanupgroup = NULL;
rollback = 0;
bool bRet = false;
pool = CreateThreadpool(NULL);
if(NULL == pool)
{
goto cleanPool;
}
rollback = 1;
SetThreadpoolThreadMaximum(pool, 5);
bRet = SetThreadpoolThreadMinimum(pool, 10);
if (FALSE == bRet) {
goto cleanPool;
}
cleanupgroup = CreateThreadpoolCleanupGroup();
if (NULL == cleanupgroup) {
goto cleanPool;
}
rollback = 2;
SetThreadpoolCallbackPool(&CallBackEnviron, pool);
SetThreadpoolCallbackCleanupGroup(&CallBackEnviron,
cleanupgroup,
NULL);
return ;
cleanPool:
switch (rollback)
{
case 2:
// Clean up the cleanup group.
CloseThreadpoolCleanupGroup(cleanupgroup);
case 1:
// Clean up the pool.
CloseThreadpool(pool);
default:
break;
}
return ;
}
void foo()
{
PTP_WORK work = NULL;
work = CreateThreadpoolWork(ClassA::_delegate,
NULL,
&CallBackEnviron);
}
static void __stdcall _delegate(PTP_CALLBACK_INSTANCE Instance, PVOID Parameter, PTP_WORK Work)
{
//some code
}
PTP_POOL pool;
UINT rollback;
TP_CALLBACK_ENVIRON CallBackEnviron;
PTP_CLEANUP_GROUP cleanupgroup;
};
int main()
{
ClassA a;
a.init();
a.foo();
}
If you make a project and execute this code, it gets unhandled execption...
I have no clue why...
I think the exception is caused by an uninitialized structure CallBackEnviron. The documentation states that this structure must be initialized by InitializeThreadpoolEnvironment

Resources