Thread Synchronization in C++11

1. Tried condition_variable to signal from one to another. Something like one of sync objects (event, mutex, critial section, …) and WaitForSingleObject() in Windows. Lambda in the cond.wait() was called twice. How should I remove the 1st call by creating unsignaled cond?

code:

mutex mtx;
condition_variable cond;
bool done = false;

thread t = thread([&]() {
	// define _GLIBCXX_USE_NANOSLEEP
		this_thread::sleep_for(chrono::seconds(2));
		cout << "[" << this_thread::get_id() << "] notifying" << endl;
		done = true;
		cond.notify_one();
	});

thread t2 = thread([&]() {
	cout << "[" << this_thread::get_id() << "] waiting..." << endl;
	unique_lock<mutex> lock(mtx);
	cond.wait(lock, [&]() {
				cout << "[" << this_thread::get_id() << "] notified. done=" << done << endl;
				return done == true;
			});
});

t.join();
t2.join();
cout << "all done" << endl;

output:

[0x105bcb000] waiting...
[0x105bcb000] notified. done=0
[0x105b48000] notifying
[0x105bcb000] notified. done=1
all done

2. Borrowed rendezvous from here to suspend all threads until specified number of threads call wait(), then resume running them.

code:

const int numThreads = 10;
rendezvous r(numThreads + 1);
mutex mtx;

vector<thread> threads(numThreads);
for (int i : range(0, numThreads)) {
	threads[i] = thread([&]() {
		this_thread::sleep_for(chrono::seconds(2));
		{
			lock_guard<mutex> guard(mtx); // just to synchronize print output
			cout << "[" << this_thread::get_id() << "] done" << endl;
		}
		r.wait();
	});
}

r.wait();
cout << "all done" << endl;
for (int i : range(0, numThreads)) {
	threads[i].join();
}

output:

[0x10a83c000] done
[0x10a942000] done
[0x10a8bf000] done
[0x10a9c5000] done
[0x10aa48000] done
[0x10aacb000] done
[0x10ab4e000] done
[0x10abd1000] done
[0x10a736000] done
[0x10a7b9000] done
all done

Thread in C++11

Yesterday’s bug marks got almost disappeared by adding -std=c++11 in Preprocessor Include Path,

However it’s not perfect. For example, thread::join() should be valid and there is no error mark at ‘t.join()’. But if you store the handle in vector element t2, it says ‘Method “join” could not be resolved” although it’s valid 🙁

Anyway, I tried C++11 threads. I borrowed range from here.

void thread_test() {
	const int numThreads = 10;
	mutex mtx;

    vector<thread> threads(numThreads);
    for(int i:range(0,numThreads)){
    	threads[i] = thread([&mtx]() {
    		lock_guard<mutex> guard(mtx);
    		cout << "[" << this_thread::get_id() << "] Hoge!" << endl;
    	});
    }

    for(int i:range(0,numThreads)){
    	threads[i].join();
    }
}

Enabling C++11

I got a clang LLVM 1.0 error when compiling C++ Lambda with Xcode 4.3.3. It seems Xcode 4.3 doesn’t support it although the latest clang supports it. So, I installed gcc4.7 which supports it.

sudo port install gcc_select
sudo port install gcc47
sudo port select gcc mp-gcc47

It worked in a terminal, but didn’t work well with Eclipse which needed the following settings.

1. Right click on your project -> properties -> C/C++ build -> Environment -> add "PATH = /opt/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:".
2. project -> properties -> C/C++ Build -> Tool Chain Editor -> Choose Linux GCC.
3. project -> properties -> C/C++ Build -> Settings -> Tool Settings -> GCC C++ Compiler -> Miscellaneous -> Tool Sttings -> add "-std=c++11"


One more thing, but I don’t know how to resolve the following false positive errors although compile succeeds.

Finally I can experiment C++11 features. I began with Lambda, auto, range-based for loop.

void lamda_test()
{
   auto f = [](){};
   f(); // do nothing

   int ar[] = {1, 2, 3, 4, 5};
   auto f2 = [=]() { for(auto& i:ar) { cout << i << endl;} };	// capture ar (value)
   f2(); // print 1,2,3,4,5

   vector<int> v;
   for (int i = 0; i < 10; i++) {
       v.push_back(i);
   }
   int sum = 0;
   for_each(v.begin(), v.end(), [&](int x) { sum += x; }); // capture sum by '&'(reference)
   cout << sum << endl; // print 45
}

C++98 recap

I needed to run through old C++98 before learning new C++11 features.

code

struct is_even : unary_function<int, bool> {
    bool operator()(int x) const
    {
        return x % 2 == 0;
    }
};

struct buggy_plus : binary_function<int, int, int> {
    int operator()(int a, int b) const
    {
        return a + b + 1;
    }
};

void Hoge::TestFunctionObjects()
{
    // standard function objects
    plus<int> plus;
    minus<double> minus;

    cout << "plus(2,3) = " << plus(2, 3) << endl;
    cout << "minus(2.0f,0.2f) = " << minus(2.0f, 0.2f) << endl;

    // custom unary function objects
    is_even even;
    unary_negate<is_even> odd(even);

    cout << "Is 2 even? " << even(2) << endl;
    cout << "Is 2 odd? " << odd(2) << endl;

    // custom binary function objects
    buggy_plus bplus;
    cout << "bplus(2,3) = " << bplus(2, 3) << endl;

}

void Hoge::TestAlgorithm()
{
    vector<int> v;
    for (int i = 0; i < 10; i++) {
        v.push_back(i);
    }

    // algorithm
    sort(v.begin(), v.end(), greater<int>());
    cout << "---" << endl;
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << endl;
    }

    // remove_if doesn't remove the element, but swap the matched ones to backword and return the last pointer
    vector<int>::iterator last = remove_if(v.begin(), v.end(), bind2nd(less<int>(), 5));

    cout << "---" << endl;
    for (vector<int>::iterator it = v.begin(); it != last; it++) {
        cout << *it << endl;
    }
}

result

* function objects
plus(2,3) = 5
minus(2.0f,0.2f) = 1.8
Is 2 even? 1
Is 2 odd? 0
bplus(2,3) = 6
* algorighm
---
9
8
7
6
5
4
3
2
1
0
---
9
8
7

HTML Encoder in Pasteboard

Before posting more, I needed an html encoder in Pasteboard to change <,>,&,… into <,>&… before pasting into in <pre>code-here</pre>.

I copy text/code into Pasteboard by cmd+c, run the program and cmd+v to paste the encoded string.

AppDelegate.m

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSPasteboard*  pasteBoard  = [NSPasteboard generalPasteboard];
    // get string from the pasteboard
    NSString* copiedString = [pasteBoard stringForType:NSPasteboardTypeString];
    // html encode
    NSString* encodedString = [NSString HtmlEncode:copiedString];
    // copy it into the pasteboard
    [pasteBoard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil];
    [pasteBoard setString:encodedString forType:NSStringPboardType];
    
    // quit the app
    [[NSApplication sharedApplication] terminate:self];
}

NSString+HTML.h/.m

#import <Foundation/Foundation.h>

@interface NSString (HTML)

+ (NSString*)HtmlEncode:(NSString*)htmlString;

@end

#import "NSString+HTML.h"

@implementation NSString (HTML)

+ (NSString*)HtmlEncode:(NSString*)htmlString {
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"&"  withString:@"&amp;"];
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"<"  withString:@"&lt;"];
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@">"  withString:@"&gt;"];
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"""" withString:@"&quot;"];    
    htmlString = [htmlString stringByReplacingOccurrencesOfString:@"'"  withString:@"&#039;"];
    return htmlString;
}

@end

16/32bit hello world

Continuation of the MASM book. Built 16/32bit exe.

hello16.asm

.286
.model small

end_process macro ret_value
            mov   al, ret_value
            mov   ah, 4ch
            int   21h
            endm

display     macro string
            mov   dx, offset string
            mov   ah, 09h
            int   21h
            endm

; AL <- keycode
read_kbd    macro
            mov   ah, 08h
            int   21h
            endm

.data
MSG         db 'Hello 16bit world.', 0dh, 0ah, '$'
MSG2        db '(hit any key).', 0dh, 0ah, '$'
MSGKEY      db '" " typed.', 0dh, 0ah, '$'

.code
START:
            mov   ax, _DATA
            mov   ds, ax

            display     MSG   ; Display message
            display     MSG2  ; Display message
            read_kbd          ; Wait for input

            mov [MSGKEY+1], AL
            mov BX, offset MSGKEY
            
            display     MSGKEY   ; Display
            end_process 0     ; exit


end START ; end

hello32.asm

; for pentium
.586
.model flat, stdcall
; ExitProcess != exitprocess with the option
option casemap:none

NULL            EQU 0
MB_OK           EQU 0
NUM             EQU 1

wsprintfA       proto c :dword, :dword, :dword, :dword, :dword
MessageBoxA     proto :dword, :dword, :dword, :dword
ExitProcess     proto :dword

.data

TITLE0          DB 'Assembler Test', 0
MESSAGE         DB 'Hello 32bit world!', 0
BUFFER          DB 64 DUP(0)

.code
WinMainCRTStartup   proc
    mov eax, NUM
    mov ecx, 10

MYLOOP:
    mov ebx, eax
    add eax, ebx
    dec ecx
    jnz MYLOOP

    ; offset -> address of the variable
    invoke MessageBoxA, NULL, offset MESSAGE, offset TITLE0, MB_OK
    invoke ExitProcess, 0

    ret
WinMainCRTStartup   endp
end

makefile

HELLO16 = hello16.exe
HELLO32 = hello32.exe

HELLO16OBJS = hello16.obj
HELLO32OBJS = hello32.obj

LDFLAGS = /LIBPATH:"C:\Program Files\Microsoft SDKs\Windows\v7.0A\Lib" /LIBPATH:"C:\Program Files\Microsoft Visual Studio 10.0\VC\lib"

hello16 : $(HELLO16OBJS)
	link16 $(HELLO16OBJS),$(HELLO16);

hello32 : $(HELLO32OBJS)
	link /NOLOGO /SUBSYSTEM:WINDOWS $(HELLO32OBJS) $(LDFLAGS) kernel32.lib user32.lib /OUT:$(HELLO32)
	
clean:
	del /f *.obj *.o *.exe *.lst

.SUFFIXES: .a16 .asm .obj

.a16.obj: 
	ml /c /Fl $<

.asm.obj: 
	ml /c /coff /Cp /nologo /Fl $< /Zi

MS-DOS COM

Read an old MASM book and build the first MS-DOS COM file. You need to donwnload 16bit linker to compile, and need exe2bin to convert from exe to com.

It sets AH/DL for Console input and does INT 21H to call it. Loops if no input (AL=0H).
CPU usage of NTVDM.exe (16bit host) was 25% on the 4CPU machine for the first 5-6 seconds (because it’s looping), then went down to 0%. Why?

AH=06H , DL=0FFH -> Console input (will get the char code in AL)
INT 21H -> DOS system call (no echo, no wait)

    MOV AH,06H
    MOV DL,0FFH
    INT 21H

Similarly, it sets AH=09H, DL= & does INT 21H to print it later. Then, AH=4CH means ‘process exit’ and AL=00H is the return code.

comtest.a16

.286

ASSUME CS:CODE,DS:CODE
CODE SEGMENT
    ORG 100H
START:
    MOV BX,0
NOINPUT:
    MOV AH,06H
    MOV DL,0FFH
    INT 21H
    JNZ PRINT
    INC BX
    CMP BX,5
    JGE START
    JMP NOINPUT
 PRINT:
    SHL BX,1
    MOV DX,TABLE[BX]
    MOV AH,09H
    INT 21H
    
    MOV AH,4CH
    MOV AL,00H
    INT 21H

FAIR    DB  'FAIR',0DH,0AH,'$'
CLOUDY  DB  'CLOUDY',0DH,0AH,'$'
RAINY   DB  'RAINY',0DH,0AH,'$'
RLATER  DB  'RAINY LATER CLOUDY',0DH,0AH,'$'
CLATER  DB  'CLOUDY LATER RAINY',0DH,0AH,'$'

TABLE   DW  OFFSET FAIR, OFFSET CLOUDY, OFFSET RAINY
        DW  OFFSET RLATER, OFFSET CLATER

 CODE ENDS
    END START

comtest.mak

COMTEST = comtest.exe
COMTESTCOM = comtest.com

COMTESTOBJS = comtest.obj

all : comtest

comtest : $(COMTESTOBJS)
	link16 $(COMTESTOBJS),$(COMTEST);
	exe2bin $(COMTEST) $(COMTESTCOM)

clean:
	del /f *.obj *.o *.exe *.lst

.SUFFIXES: .a16 .asm .obj

.a16.obj: 
	ml /c /Fl $<

.asm.obj: 
	ml /c /coff /Cp /nologo /Fl $< /Zi

How Syslog can lose data

From Rainer’s Blog. It looks syslog assumes data sent whenTCP send() was successful by design.

Simulated the behavior and confirmed by running below one in client mode & the other in server mode. When you kill the server process & run it again while client process is running, you’ll see a message lost.

import sys
import SocketServer
import socket
import time

def usage():
    print "%s [client | server]" % sys.argv[0]
    
def server(HOST, PORT):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((HOST, PORT))
    sock.listen(1)
    (conn, sa) = sock.accept()
    try:
        while True:
            msg = conn.recv(8192)
            print "* received '%s'" % msg
            if len(msg) == 0:
                break;
    except socket.error, e:
        print 'Error: %s' % e
    
    conn.close()

def client_connect(HOST, PORT):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect((HOST, PORT))
    except socket.error, e:
        print "Error: %s" % e
        return None
    
    return sock

def client(HOST, PORT):
    sock = None
    i = 0
    while i< 10:
        if sock == None:
            print "connecting..."
            sock = client_connect(HOST, PORT)
        if sock == None:
            print "no connection. sleeping..."
            time.sleep(3)
            continue
        
        data = "* hoge %d" % i
        print "sending %s" % data
        
        try:
            ret = sock.send(data)
            
            print "Sent:     %s, return: %d" % (data, ret)
            i = i + 1
        except socket.error, e:
            print 'Error: %s' % e
            sock.close()
            sock = None
        print "sleeping..."
        time.sleep(1)

    sock.shutdown(socket.SHUT_RDWR)
    sock.close()

def main():
    if len(sys.argv) != 2:
        usage()
        return

    HOST, PORT = "localhost", 9999

    if sys.argv[1].lower() == "server":
        print "running server..."
        server(HOST, PORT)
    else:
        print "running client..."
        client(HOST, PORT)

if __name__ == "__main__":
    main()

Zabbix Agent for Windows

Downloaded the latest Windows binary and ran it with windows config in the source tar file.

Defined server address – one for passive and the other for active monitoring. Then added perf counter and files.

Server=hogehoge
ServerActive=hogehoge

Created “Windows Eventlog” application to store event logs.

Successfully configured file monitor. Notice that no single or double quote supported!

 log[c:\users\sokoide\hoge.log]

Zabbix Install

Installed Zabbix on ubuntu on Parallels since I didn’t mess up Mac env.

install:

sudo apt-get install zabbix-server-mysql -y
sudo apt-get install zabbix-agent -y
sudo apt-get install zabbix-frontend-php -y

config files:

/etc/zabbix/zabbix_server.conf
/etc/zabbix/zabbix_agent.conf

default log path:

/var/log/zabbix

web frontend:

http://$hostname/zabbix

(default username: Admin, password: zabbix)

stop/start:

sudo service zabbix-server start
sudo service zabbix-server stop

Will configure Windows agent later.

1 5 6 7 8