Страницы

Поиск по вопросам

пятница, 5 июля 2019 г.

Многопоточный epoll

Написал код с epoll_create1(0); epoll_ctl(); epoll_wait(); и при вызове epoll_wait(); из двух потоков с удивлением вижу, что они возвращают одинаковые сокеты.
Мне казалось, что epoll можно использовать из разных потоков. Я не прав? Как получить многопоточный epoll? Есть ли стандартное решение или он просто заменяет select() и многопоточность нужно реализовывать самому?


Ответ

Все оказывается до банальности просто, достаточно использовать флаг EPOLLONESHOT в epoll_ctl() и сокет будет выдаваться один раз.

Система плагинов

Захотелось научиться работать с отражением и вот этим всем. Начал с простенького, решил написать подключаемый плагин, который автоматически подгрузится из именной папки.
Что бы не мучиться с отражением методов и прочей нечистью на ум конечно же приходит наследование и полиморфизм. То есть мне нужен какой-то базовый класс с начальным функционалом от которого будут наследоваться все другие плагины.
То есть нужно сделать отдельную библиотеку с апи, которую будут использовать обе стороны (программа и плагин).
public interface IPlugin { void Loaded(); }
Вот такой класс придумал в этой библиотеке. Теперь я могу спокойно ее подключать к плагину и наследоваться.
public class Test : IPlugin { #region Implementation of IPlugin
public void Loaded() => Console.WriteLine( "Hello World" );
#endregion }
Вот у меня уже две библиотеки, одна с моим апи, другая его использует. Теперь мне нужно как-то загрузить сборку с плагином и использовать его методы. Вот тут мне и нужна помощь.
Так как библиотека плагина использует другую библиотеку с апи, я не смогу ее так просто загрузить, так как выскочит ошибка мол либе не хватает референсов. Как правильно загрузить плагин указав что сборка которая ему нужна уже загружена в программу?
Вот код которым я пытаюсь что-то наколдовать:
private static void Main ( string[] args ) { var pluginsPath = $"{Directory.GetCurrentDirectory()}\\Plugins"; var files = Directory.GetFiles( pluginsPath , "*.dll" );
foreach ( var file in files ) { Console.WriteLine( $"Trying load: {file}" ); Assembly assembly;
try { assembly = Assembly.Load( file ); } catch ( Exception ex ) { Console.WriteLine( ex.Message ); continue; }
var types = assembly.GetTypes().Where( type => type.IsClass && type.GetInterface( nameof( IPlugin ) ) != null );
foreach ( var type in types ) { var plugin = Activator.CreateInstance( type ) as IPlugin;
if ( plugin == null ) { Console.WriteLine( "Null" ); continue; }
plugin.Loaded(); } } }
Падает еще на первом try с сообщением:
Необработанное исключение типа "System.IO.FileLoadException" в mscorlib.dll Дополнительные сведения: Не удалось загрузить файл или сборку "C:\Users\anweledig\Documents\Visual Studio 2015\Projects\Anweledig\ConsoleApplication\bin\Debug\Plugins\TestPlugin.dll" либо одну из их зависимостей. Данное имя сборки или база кода недействительны. (Исключение из HRESULT: 0x80131047)


Ответ

Вы можете просто загрузить другую библиотеку. Все ее зависимости будут автоматически загружены.
Проблема может быть только в случае, если библиотека лежит не в той же папке, в которой лежит ваше приложение, и вы при этом загружаете ее через Assembly.LoadFrom. Чтобы это обойти, вам нужно указать рантайму что зависимости надо искать в папке плагина, а не в папке вашего приложения. Тогда можно будет использовать обычный Assembly.Load и заодно заработает станадартный механизм загрузки сборок.
Для этого можно использовать создание аппдомена с указанием AppDomainSetup.ApplicationBase
Т.е. схема примерно такая:
У вас есть базовая dll для плагинов - MyApp.SDK, в ней базовый класс (а лучше - интерфейс):
public abstract class Plugin { public abstract void Loaded(); public abstract void Unload(); }
в ней же код загрузки и вызова плагина (для простоты)
public static class PluginInvoker { public static void InvokePlugin() { var pluginAssembly = Assembly.Load("SomePlugin"); var pluginType = pluginAssembly.GetTypes().Where(t => typeof(Plugin).IsAssignableFrom(t)).Single(); Plugin plugin = (Plugin)pluginType.GetConstructor(new Type[0]).Invoke(null); plugin.Loaded(); } }
есть реализация этого плагина в SomePlugin.dll:
public class Test: MyApp.SDK.Plugin { public override void Loaded() { Console.WriteLine("Loaded"); }
public override void Unload() { Console.WriteLine("Unloaded"); } }
в SomePlugin есть референс на MyApp.SDK.
И есть главное приложение, в котором есть ссылка на MyApp.SDK, но нет ссылки на SomePlugin:
static void Main(string[] args) { AppDomainSetup setup = new AppDomainSetup(); setup.ApplicationBase = @"C:\Projects\MyApp\SomePlugin\bin\Debug\";
AppDomain pluginDomain = AppDomain.CreateDomain("plugin", null, setup); pluginDomain.DoCallBack(PluginInvoker.InvokePlugin); }
ApplicationBase задает папку, откуда AppDomain будет загружать сборки - т.к. это папка плагина, то все, на что он ссылается, будет корректно загружено.
Если плагины подгружаются из подпапки приложения (например, из Plugins), то в вместо AppDomainSetup.ApplicationBase можно использовать AppDomainSetup.PrivateBinPath
Если же при этом плагины вообще не планируется выгружать, и все плагины лежат в одной папке (без подпапок на каждый из плагинов) - то можно обойтись без отдельного AppDomain, просто дописав путь к папке с плагинами в секцию app.config/
код примера на github: https://github.com/PashaPash/PluginLoadSample

Функция вызывается с неправильными значениями переменных

Суть вопроса такова. Есть такой код:
#include "stdafx.h"
#define PI 3.1415926535897932384626433832795 #define FR 3 #define SAMPLES 1024
int _tmain(int argc, _TCHAR* argv[]) { base signal[SAMPLES];
for (int i = 0; i < SAMPLES; ++i) { signal[i] = (sin(2*PI*i*FR), 0); }
FFTCalculate(signal, SAMPLES, false);
FILE* f_pointer = fopen("fft_result.txt", "w");
for (int i = 0; i < SAMPLES; ++i) { char num = (char)signal[i].real(); int out = fprintf(f_pointer, &num); } int out = fclose(f_pointer); return 0; }
в нем вызывается функция FFTCalculate(signal, SAMPLES, false). Ниже приведен код функции:
void FFTCalculate(base signal[], int n, bool invert) { int log_N; double x = frexp((double)n, &log_N);
calc_rev(n, log_N);
for(int i = 0; i < n; ++i) if (i < rev[i]) swap(signal[i], signal[rev[i]]);
for(int len = 2; len <= n; len<<=1) { double ang = 2*PI/len * (invert?-1:1); int len2 = len>>1;
base wlen (cos(ang), sin(ang)); wlen_pw[0] = base(1, 0); for (int i=0; i for (int i=0; i for(; pu != pu_end; ++pu, ++pv, ++pu){ t = *pv * *pw; *pv = *pu - t; *pu += t; } } } if(invert) for (int i=0; iПри запуске программы появляется ошибка, связанная с выходом за пределы массива. Начал дебажить и выяснил, что когда вызывается функция FFTCalculate(signal, SAMPLES, false), то ей почему то передаются не signal, SAMPLES = 1024 и false, а sugnal, 1245452 и true см. скриншот ниже. В чем дело?


Ответ

Я проверил на GCC 4.8.2 под linux. Параметры FFTCalculate передаются корректно. Думаю что, то поведение которое ты видишь в Visual Studio является unexpected behavior. Твоя программа под линуском сразу упала с seg fault.
Ниже пример кода с ошибкой. Ты не проверяешь значения rev[i], что оно может быть больше n (1024).
calc_rev(n, log_N);
for(int i = 0; i < n; ++i) if (i < rev[i]) swap(signal[i], signal[rev[i]]);
Вот что у меня вывелось для первых десяти итераций из массива rev: 0 1024 1536 1280 1792 1152 1664 1408 1920
Надеюсь помог.

Странное поведение оператора >>

Решил попробовать в работе библиотеку JsonCpp, написал простенькую программу:
#include #include int main() { Json::Value val; std::cin >> val["foo"]; //вот здесь странно себя ведет. std::cout << val; }
Но после компиляции и запуска программа не доходит до вывода root, а бесконечно дает вводить текст. Очевидно, проблема в строке std::cin >> val["foo"], но строка взята из примера в документации, и там та же проблема. Даже не могу представить, в чем может быть проблема. Здесь в самом низу (последняя функция) можно увидеть реализацию этого самого operator>>


Ответ

Дело вот в этой строке в библиотеке:
ssin << sin.rdbuf();
Это яд: она пытается скопировать весь файл целиком, поэтому чтобы закончить ввод, вы должны скормить терминалу EOF (^D на никсах, ^Z на Windows). Короче говоря, не используйте эту функцию, а еще лучше не используйте эту библиотеку - rapidjson, например, не страдает от таких дефектов.

Скрывающийся при прокрутке ActionBar (ToolBar)

Недавно я задался вопросом, как реализована анимация в мобильном приложении Twitter.
При прокручивании ленты вверх, нижняя панель, предназначенная для ввода твита, очень плавно уходит вниз. Если при движении вверх остановиться на том моменте когда панель ушла только на половину и убрать палец, она автоматически скроется. При прокручивании ленты вниз происходит обратное действие.
Подобного рода анимация мною была также замечена в приложении Play Market. При переходе в любую категорию (например игры), при прокручивании вниз плавно скрывается ActionBar
Я попытался реализовать подобную вещь с использованием transition-анимации и обычного вертикального LinearLayout, в котором много элементов. Также я использовал OnScrollChangedListener. Ничего не получилось.
Подскажите пожалуйста как можно реализовать подобную анимацию и если можно пример реализации!


Ответ

Совсем недавно была представлена библиотека поддержки от google - support:design , в которую, помимо прочих нужных вещей, входит новый виджет: CollapsingToolbarLayout - данный виджет реализует требующуюся вам функциональность от производителя. Подробности использования данного виджета вы можете посмотреть в релизе к этой библиотеки , раздел Collapsing Toolbars
Ранее лучше всего такой эффект был реализован в библиотеке ObservableScrollView , если вы непременно задались целью реализовать этот эффект самостоятельно - изучите ее исходники, в разумных размерах это не опишешь.

Редирект с HTTP на HTTPS в IIS 8.5

Установил Url Rewrite 2.0 и сделал по инструкции данный редирект. В веб конфиге получилось так:


Но возникает ошибка TOO MANY REDIRECTS


Ответ

Я обычно делаю так:

Изменение CSS свойств scale и zoom у элемента

Как задать шаг изменения CSS свойств scale и zoom у элемента $('img')?
$(document).ready(function() { $(document).keypress(function(event) { a = $('img').height(); //height b = $('img').width(); //width
c = parseInt(a) + 10; //width plus one step Intvalue d = parseInt(b) + 10; //height plus one step Intvalue
e = parseInt(a) - 10; //width minus one step Intvalue f = parseInt(b) - 10; //height minus one step Intvalue
if (event.keyCode == 107) { //scale или zoom вместо width и height
$('img').css('width', d + 'px') //change css Intvalue + "px" $('img').css('height', c + 'px') //change css Intvalue + "px" } if (event.keyCode == 109) { //scale или zoom вместо width и height
$('img').css('height', e + 'px')//change css Intvalue + "px" $('img').css('width', c + 'px')//change css Intvalue + "px" } })


Ответ

Идея реализация весьма схожа с предыдущим вопросом. Отличиями являются наличие parseFloat() (потому что .css('свойство') возвращает String) и использование регулярного выражения (взятого из этого вопроса) для получения значений scale из transform.
HTML:


CSS:
#img1 { position: absolute; margin: auto; top: 0; left: 0; bottom: 0; right: 0; width: 300px; height: 300px; zoom: 100%; transform: scale(1, 1); }
JS:
$(document).ready(function() { $(document).on("keypress", function(event) { var image = $('img'); var imageZoom = parseFloat(image.css('zoom')); var imageTransform = image.css('transform'); var matrixRegex = /matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*(-?\d*\.?\d+),\s*0,\s*0\)/, matches = imageTransform.match(matrixRegex); var scaleX = parseFloat(matches[1]); var scaleY = parseFloat(matches[2]); if (event.which == 43 || event.which == 45) { var zoomChange = (event.which == 43) ? 0.1 : -0.1; var scaleChange = (event.which == 43) ? 0.1 : -0.1; image.css('zoom', imageZoom + zoomChange); image.css('transform', 'scale(' + (scaleX + scaleChange) + ',' + (scaleY + scaleChange) + ')'); } }); });
Пример в fiddle