“If you’re an experienced C++ programmer and are anything like me, you initially approached C++11 thinking, “Yes, yes, I get it. It’s C++, only more so.” But as you
learned more, you were surprised by the scope of the changes. auto declarations, range-based for loops, lambda expressions, and rvalue references change the face of C++, to say nothing of the new concurrency features. And then there are the idiomatic changes. 0 and typedefs are out, nullptr and alias declarations are in. Enums should now be scoped. Smart pointers are now preferable to built-in ones. Moving objects is normally better than copying them.
– Effective Modern C++ by Scott Meyers
Effective Modern C++ by Scott Meyers
Обнаружение дедлока из шелл-скрипта
Задача: Обнаружим дедлок bash-скриптом и отдадим на выход exitcode 1.
Вос/произведем простейший дедлок, запустим ./ily.bin deadlock_off 1000000
ily.cpp:
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#include <iostream> #include <thread> #include <mutex> // множитель. Увелич.кратно 10 для увеличения продолжительности работы программы, можно передать в argv long SIZE = 10000; std::mutex mu1, mu2; // выставить в 1 для дедлока, можно передать в argv int deadlock_is_on = 0; static void shared_func1() { std::lock_guard<std::mutex> guardA(mu1); std::lock_guard<std::mutex> guardB(mu2); std::cout << std::this_thread::get_id() << std::endl; } static void shared_func_deadlock() { std::lock_guard<std::mutex> guardA(mu2); std::lock_guard<std::mutex> guardB(mu1); std::cout << std::this_thread::get_id() << std::endl; } void function_1() { long neg_size = -SIZE; for (int i = 0; i > neg_size; i--) shared_func1(); } int main(int argc, char* argv[]) { std::cout << "Pass X as command line argument to turn deadlocks on" << std::endl; if (argc > 1) if (std::string(argv[1]) == "X") deadlock_is_on = 1; if (argc > 2) SIZE = atoi(argv[2]); std::thread t1(function_1); for (int i = 0; i < SIZE; i++) if (deadlock_is_on) shared_func_deadlock(); else shared_func1(); t1.join(); return 0; } |
Дедлок вычислим силами GDB – для этого подготовим следующий скрипт (futex_gdb_py), так как gdb поддерживает питон (через import gdb находим pthread_mutex_lock прямо в gdb)
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 30 31 32 33 34 35 36 37 38 39 40 41 |
python import sys sys.path.append('.') import gdb class Thread(): def __init__(self): self.frames = [] self.waitOnThread = None self.threadId = None def __getitem__(self): return self.waitOnThread threads = {} for process in gdb.inferiors(): for thread in process.threads(): trd = Thread() trd.threadId = thread.ptid[1] #[1] - threadId; [0] - process pid thread.switch() frame = gdb.selected_frame() while frame: frame.select() name = frame.name() if name is None: name = "??" if "pthread_mutex_lock" in name: trd.waitOnThread = int(gdb.execute("print mutex.__data.__owner", to_string=True).split()[2]) trd.frames.append(name) frame = frame.older() threads[trd.threadId] = trd for (tid,thread) in threads.items(): if thread.waitOnThread: # нашли дедлок if thread.waitOnThread in threads and threads[thread.waitOnThread].waitOnThread == thread.threadId: sys.exit(1) # Получим на выходе из gdb exitcode "1" end thread apply all where |
команда x/3d
команда x/3d
команда thread 4 показывает что процесс 20860 ждет mutex2
команда thread 5 показывает что процесс 20861 ждет mutex1:
И, собственно сам скрипт bash, для простоты берём pid запущенного процесса по имени ily.bin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/bin/bash function run() { bin_name=$1 bin_pid=$(pgrep $bin_name) gdb -q $bin_name $bin_pid -x futex_gdb_py -batch exitcode=$? if [ $exitcode = 0 ]; then echo "Passed!" elif [ $exitcode = 1 ]; then echo "Failed!" fi } echo "Running test #1" run ily.bin |
Cortex-M3/M4 [Olimex STM32-P152] GCC + OpenOCD с PN2
Olimex STM32-P152
Среда разработки – Eclipse + GCC (исходный код G ++ Lite) / Atollic TrueSTUDIO + ST-Link/V2
(с) kenjia
Microsoft UI Automation
Каким образом програмно получить значение поля Tag из программы Pilot-BIM? Т.к. программа написана на dotNet, её GUI “подчиняется” модели автоматизации пользовательского интерфейса Microsoft.
Соответственно, берём UISpy и ищем наше поле:
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 30 31 32 33 34 35 36 37 38 39 40 |
using namespace System; using namespace System::Windows::Automation; #include "Program.h" namespace uiAutomat { ref class CMain { static int main(array<System::String*>* args) { PropertyCondition* findWindow = gcnew PropertyCondition(AutomationElement::AutomationIdProperty, "mainPilotView"); AutomationElement* window = AutomationElement::RootElement->FindFirst(TreeScope::Children, findWindow); PropertyCondition* pcPropertiesDataGrid = gcnew PropertyCondition(AutomationElement::AutomationIdProperty, "ObjectPropertiesDataGrid"); AutomationElement* ObjectPropertiesDataGrid = window->FindFirst(TreeScope::Descendants, pcPropertiesDataGrid); ScrollPattern* scrollPattern = (ScrollPattern)ObjectPropertiesDataGrid->GetCurrentPattern(ScrollPatternIdentifiers::Pattern); scrollPattern->ScrollVertical(ScrollAmount::LargeIncrement); /* PageDown */ PropertyCondition* pcPset_ElementInformation = gcnew PropertyCondition(AutomationElement::NameProperty, "Pset_ElementInformation"); AutomationElement* Pset_ElementInformation = ObjectPropertiesDataGrid->FindFirst(TreeScope::Descendants, pcPset_ElementInformation); PropertyCondition* pcTagRow = gcnew PropertyCondition(AutomationElement::NameProperty, "Tag"); AutomationElement* AEl_Tag = Pset_ElementInformation->FindFirst(TreeScope::Descendants, pcTagRow); PropertyCondition* pcGridCell = gcnew PropertyCondition(AutomationElement::AutomationIdProperty, "AUIDPropertyValueCell"); AutomationElement* AUIDPropertyValueCell = AEl_Tag->FindFirst(TreeScope::Descendants, pcGridCell); PropertyCondition* pcText = gcnew PropertyCondition(AutomationElement::ClassNameProperty, "TextBlock"); AutomationElement* AEl_Text = AUIDPropertyValueCell->FindFirst(TreeScope::Descendants, pcText); String* TAGTAG = reinterpret_cast<String*>(AEl_Text->GetCurrentPropertyValue(AutomationElement::NameProperty)); return 0; } }; /* <-- semicolon because main() of CLR++ should be wrapped in a class like CMain */ } |
Программа для запоминания ключей 部首
Программа Chi[tai]na предназначена для запоминания 214-ти китайских ключей (упрощённое письмо – chinese simplified).
Программа выводит в случайном порядке четыре различных ключа, давая описание одного из них.
При нажатии на правильный ключ воспроизводится его произношение и порядок написания черт.
ST STM32L152VBT6A support in PlatformIO
OLIMEX STM32-P152 board
JRE as Eclipse plugin
eclipse.ini:
1 2 |
-vm plugins/org.eclipse.justj.openjdk.hotspot.jre.full.win32.x86_64_15.0.2.v20210201-0955/jre/bin |
UPD:
org.eclipse.justj.openjdk.hotspot.jre.full-22.0.1-linux-x86_64.tar.gz
org.eclipse.justj.openjdk.hotspot.jre.full-22.0.1-win32-x86_64.tar.gz
Old links:
org.eclipse.justj.openjdk.hotspot.jre.full-19.0.2-linux-x86_64.tar.gz
org.eclipse.justj.openjdk.hotspot.jre.full-19.0.2-win32-x86_64.cab
Creating WDM and driver call
Let’s create a WDM driver and some application to call it (e.g. MFC)
WDM’s source.c
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
#include "ntddk.h" #define DEVICE_SEND CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_WRITE_DATA) #define DEVICE_REC CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_READ_DATA) UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\drv_call_wdm"); UNICODE_STRING SymLinkName = RTL_CONSTANT_STRING(L"\\??\\drv_call_wdm_link"); // UNICODE_STRING SymLinkName = RTL_CONSTANT_STRING(L"\\DosDevices\\drv_call_wdm_link"); PDEVICE_OBJECT DeviceObject = NULL; VOID Unload(IN PDRIVER_OBJECT DriverObject) { IoDeleteSymbolicLink(&SymLinkName); IoDeleteDevice(DeviceObject); DbgPrint("Driver unload\r\n"); } NTSTATUS DispatchPassThru(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; switch (irpsp->MajorFunction) { case IRP_MJ_CREATE: DbgPrint("Create request\r\n"); /*KdPrint(("Create request\r\n"));*/ break; case IRP_MJ_CLOSE: DbgPrint("Close request\r\n"); /*KdPrint(("Close request\r\n"));*/ break; //case IRP_MJ_READ: // DbgPrint("Read request\r\n"); // KdPrint(("Read request\r\n")); // break; default: status = STATUS_INVALID_PARAMETER; break; } Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } NTSTATUS DispathDevCTL(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; ULONG returnLength = 0; PVOID buffer = Irp->AssociatedIrp.SystemBuffer; ULONG inLength = irpsp->Parameters.DeviceIoControl.InputBufferLength; ULONG outLength = irpsp->Parameters.DeviceIoControl.OutputBufferLength; WCHAR *demo = L"sample return from driver"; switch (irpsp->Parameters.DeviceIoControl.IoControlCode) { case DEVICE_SEND: DbgPrint("Send data is %ws \r\n", buffer); returnLength = (wcsnlen(buffer, 511) + 1) * 2; break; case DEVICE_REC: wcsncpy(buffer, demo, 511); returnLength = (wcsnlen(buffer, 511) + 1) * 2; DbgPrint("receive data is %ws \r\n", buffer); break; default: status = STATUS_INVALID_PARAMETER; } Irp->IoStatus.Status = status; Irp->IoStatus.Information = returnLength; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) // main { DriverObject->DriverUnload = Unload; UNICODE_STRING string = RTL_CONSTANT_STRING(L"hello driver\r\n"); DbgPrint("%wZ", &string); // printf() NTSTATUS status = IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject); if (!NT_SUCCESS(status)) { DbgPrint("Create device failed\r\n"); return status; } status = IoCreateSymbolicLink(&SymLinkName, &DeviceName); if (!NT_SUCCESS(status)) { DbgPrint("create symbolic link failed\r\n"); IoDeleteDevice(DeviceObject); return status; } for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i) { DriverObject->MajorFunction[i] = DispatchPassThru; } DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispathDevCTL; DbgPrint("Driver load\r\n"); return STATUS_SUCCESS; } |
Boost.Log: v2s_mt_nt6 doesn’t match v2s_mt_nt62
При возникновении ошибки
1 |
LNK2038: mismatch detected for 'boost_log_abi': value 'v2s_mt_nt6' doesn't match value 'v2s_mt_nt62' |
скорее всего, две библиотеки используют одни и те же директивы (#define).
Решение: просто поместите #include файла Boost выше.
Күп агымлы TCP-сәрвәр
Гади консольле TCP-клиент hәм Linux-сокетларын куллана торган сәрвәр.
Сораучы ягы боерык юлыннан өч зурлык ала:
- Сораучының исеме
- Портның номеры (әйтик, 6669)
- Тоташу вакытының озынлыгы (секундаларда)
Сораучы ягы бирелгән вакыт озынлыгы белән сәрвәргә тоташа да, hәм менә мондый форматта сәрвәргә юл җибәрә:
[yyyy-mm-dd hh:mm:ss.ms] “сораучының исеме”
Сәрвәр боерык юлыннан бер генә зурлык ала:
1) Портның номеры
Эшләтеп җибәргәннән соң сәрвәр бирелгән портны тыңлый, сораучылардан белдерүләр ала hәм аларны беркетмәгә (log.txt) яза.
Сораучының hәр тоташуы аерым агымда эшкәртелә.
hәрбер белдерү аерым юлга языла.
Сәрвәр бер үк вакытта берничә сораучы белән эшли һәм log.txt беркетмәгә язу мөмкинлеген тәэмин итә.
Мәсәлән, сәрвәрне эшләтеп җибәрәбез:
tcp_th_srv 3000
Сораучыларны җибәрәбез:
clnt80 Name1 3000 1
clnt80 Name2 3000 2
clnt80 Name3 3000 3
Ул чагында log.txt беркетмәдә якынча шундый юлларны күрербез (сораучыларны эшләтеп җибәрү вакытына бәйле булачак)
[2018-09-19 13:50:01.000] Исем1
[2018-09-19 13:50:02.000] Исем1
[2018-09-19 13:50:02.010] Исем2
[2018-09-19 13:50:03.000] Исем1
[2018-09-19 13:50:03.010] Исем3
[2018-09-19 13:50:04.000] Исем1
[2018-09-19 13:50:04.010] Исем2
[2018-09-19 13:50:05.000] Исем1
[2018-09-19 13:50:06.000] Исем1
[2018-09-19 13:50:06.010] Исем2
[2018-09-19 13:50:06.020] Исем3
Определение точки выброски парашютистов
Одним из фундаментальных навыков обеспечивающих безопасность выполнения прыжков с парашютом является умение теоретического расчета парашютирования
Траектория перемещения парашютиста после отделения от самолета состоит из двух частей: свободного падения и снижения под куполом парашюта.
После раскрытия парашюта парашютист приобретает, кроме скорости парашютирования, также и скорость ветра, с которой его будет относить по горизонту. Расстояние на земле между проекцией точки раскрытия парашюта и точкой приземления нейтрального (круглого) купола называется относом парашютиста по ветру.
На практике при расчете точки выброски в парашютных видах деятельности применяются среднеарифметический способ и практический способ (пристрелка).
\[ t_{ch}(\text{Время снижения})\frac{H(\text{Высота открытия})}{V_{CH}(\text{Скорость снижения})}=\frac{1000}{5}=200с \]
Все они приводят к определению расчетной точки, в которой нужно покинуть летательный аппарат, чтобы прийти на нейтральном куполе в намеченный район цели, а также с учетом возможной отцепки основного купола (см. рисунок).
Нейтральный купол – круглый парашют, не имеющий собственной горизонтальной скорости и снижающийся со скоростью 5 м/с.
Траектория нейтрального купола (ТНК) – предполагаемая глиссада по которой нейтральный купол снизится от точки выброски до точки приземления
(см рисунок).
Для среднеарифметического метода расчета точки начала выброски необходимы следующие данные:
- среднее направление и средняя скорость ветра, получаемые от метеослужбы;
- скорость полета летательного аппарата на выброске парашютистов (обычно 140 км/ч).
Например: высота прыжка 4000 м, высота открытия основного парашюта Н=1000 м, средняя скорость ветра VCР=8 м/c, средняя скорость снижения парашюта VСН=5 м/c.
Зная высоту открытия парашюта и среднюю скорость снижения, определим время снижения:
\[ L(\text{Относ})=t_{CH}(\text{Время снижения}) \times V_{CP}(\text{Скорость ветра}) = 200 \times 8 = 1600м \]
Таким образом, точка начала выброски парашютистов, в данных метеоусловиях, должна находиться на удалении 1600 м от намеченной точки приземления.
Корректировка полученных расчетных параметров производиться пристрелкой пробными прыжками опытных парашютистов. Первый взлет составляют из опытных спортсменов. Парашютисты с меньшим опытом, в этом случае, находятся на земле и наблюдают за работой пристрелки.
Таким образом, на основании представленного материала и выполненных исследований можно сделать следующие выводы:
- Применение методов определения точки выброски парашютистов позволяет увеличить безопасность выполнения прыжков с парашютом.
- Особое внимание необходимо уделить практическому выполнению теоретического расчета точки выброски при прыжках с парашютом.
- Отдельным вопросом стоит обучение, подготовка инструкторского состава с точки зрения методологии и практики преподносимых знаний и умений определения точки выброски для начинающих спортсменов парашютистов.