In this use case, the overall pattern for breaching capacity is A followed by B, or B followed by A when the capacity goes above or below 100 ... for which the below match_recognize code works perfectly!
expression breach { (A, B) => B.seqid > A.seqid }
select * from Event
match_recognize (
partition by tg, sy, route
measures breach(A, B) as breached, A as a, B as b
after match skip to current row
pattern (A B | B A)
define
A as A.capacity < 100,
B as B.capacity >= 100);
The only missing piece to above is, if the first event arrives that is >=100 before an event that is < 100, then the pattern should also fire (in which case I figure A would be equal to null.)
So in a nutshell ...
(B before the first A | A B | B A)
The results for the events below are captured in the comments ...
Event={seqid=0, tg="TGA", sy="IBM", route="DMA", capacity=120} // breach right off the bat ... which the pattern doesn't cover :(
Event={seqid=1, tg="TGA", sy="IBM", route="DMA", capacity=25}
Event={seqid=2, tg="TGA", sy="IBM", route="DMA", capacity=30}
Event={seqid=3, tg="TGA", sy="IBM", route="DMA", capacity=35}
Event={seqid=4, tg="TGA", sy="IBM", route="DMA", capacity=55}
Event={seqid=5, tg="TGA", sy="IBM", route="DMA", capacity=60}
Event={seqid=6, tg="TGA", sy="IBM", route="DMA", capacity=50}
Event={seqid=7, tg="TGA", sy="IBM", route="DMA", capacity=160} // breach == true for TGA/IBM/DMA
Event={seqid=8, tg="TGA", sy="IBM", route="DMA", capacity=180}
Event={seqid=9, tg="TGA", sy="IBM", route="DMA", capacity=200}
Event={seqid=11, tg="TGB", sy="IBM", route="DMA",capacity=50} // successive messages has percent drop from 200 to 50
// doesn't unbreach TGA/IBM/DMA, different partition
Event={seqid=12, tg="TGB", sy="IBM", route="DMA", capacity=60}
Event={seqid=13, tg="TGB", sy="IBM", route="DMA", capacity=70}
Event={seqid=14, tg="TGB", sy="IBM", route="DMA", capacity=110} // breaches == true for TGB/T/DMA
Event={seqid=10, tg="TGA", sy="IBM", route="DMA", capacity=40} // breach == false for TGA/IBM/DMA
I have experimented with expressions like ...
not A B
!A B
A{0} B
None of which are legal expressions in Esper.
Is there a way to create a pattern that also fires when an event first arrives and is >=100 along with the existing pattern?
(Esper notebook for this example can be found over at https://notebook.esperonline.net/#/notebook/2HSBG1CS4)
Snowflake provides a nice example of the ability to match with the beginning of a partition
pattern (^ gt75)
define
gt75 as price > 75.00
From https://docs.snowflake.com/en/user-guide/match-recognize-introduction.html#label-match-recognize-introduction-search-start-or-end-partition
If the pattern should fire without the A, then the pattern is "pattern (A B | B)".
Or alternatively just:
select * from B(capacity >= 100)
Related
Programming Project 3F
Vital signs of hospital patients are monitored and reported automatically. While each monitor has alarms which go off when a reading is out of range, combinations of readings are also important. Common vital signs and normal range is given below.
The use of functions is encouraged. If you create your own header file, name it Project3.h. This common name will allow me to easily include your header in the report I grade.
Write a program to read a series of patient records from the file PATIENTS.TXT. Use the Priming Read logic to process all records in the file. Each record (line of the file) contains the following fields delimited by a space: first name, lastname, pulse, respiration, oxygen, room. The file contains and unknown number of records. Unlike Program #2, simple stream input using >> from the file should suffice to read this file. You do not need to parse the file as you did in Project #2.
A sample file with one record per line might resemble the following
Buster Leggs 88 44 88 120
Charlie Horse 56 15 95 011
Wilma Moneylast 132 18 98 200
Willie Makit 75 30 94 121
Betty Wont 50 10 90 000
Eaton Buggs 79 16 97 111
Freda Spirit 110 23 90 220
Categorize each reading as Low, Normal or High. Print the result in the report detailed below. Normal range for each reading is as follows
Pulse 60-100
Respiration 12-20
Oxygen Level 92-100
Tag each record as according to the following and print any needed messages in the report for each record
CHECK – one indicator out of range
ALERT*** – two indicators out of range
CRITICAL***** – three indicators out of range
Room Name Pulse Respir Oxygen
120 Leggs, Buster 88 High=44 Low=88 ALERT***
011 Horse, Charlie Low= 56 15 95 CHECK
200 Moneylast, Wilma High=132 18 98 CHECK
111 Makit, Willie 75 20 94
000 Wont, Betty Low= 50 Low=10 Low=90 CRITICAL****
111 Buggs, Eaton 79 16 97
220 Spirit, Freda High=110 High=23 Low=90 CRITICAL****
Totals
2 Normal
1 ALERT
2 CHECK
2 CRITICAL
The Code I Currently have is:
\`#include "stdafx.h"
\#include \<iostream\>
\#include \<fstream\>
\#include \<string\>
\#include \<iomanip\>
using namespace std;
void Pause()
{
char junk;
cin.ignore(100,'\\n');
cout \<\< "\\n\\nPress enter to continue...";
cin.get(junk);
} // Pause()
int main()
{
//File Variables
ifstream PATIENTS_IN;
ofstream PATIENTS_LOG;
//Declare Variables and Constants
string Info, diag;
int pulseint, respint, O2int;
int count,count1, count2, count3,check, alert, critical;
string FirstName, LastName, Pulse, Resp, O2Lvl, RoomNum;
//Initalize Variables
count=0;
count1=1;
count2=0;
count3=0;
check=0;
alert=0;
critical=0;
Info= "no name read";
FirstName= "no name read";
LastName= "no name read";
// \*\* Open Data Files \*\*
PATIENTS_LOG.open("D:\\PATIENTS.log");
if(PATIENTS_LOG)
{//Last file operation was successful
}
else
{//last file operation FAILED!
cout \<\< "PATIENTS_LOG open FAILED!" \<\< endl;
}
PATIENTS_IN.open("D:\\PATIENTS.txt");
if (PATIENTS_IN)
{//last file operation was successful
PATIENTS_LOG \<\< "PATIENTS_IN file open successful" \<\< endl;
}
else
{//last file operation FAILED!
cout \<\< "PATIENTS_IN file FAILED!" \<\< endl;
}
getline(PATIENTS_IN, Info); //Priming read
if(PATIENTS_IN)
{//last file peration was successful
}
else
{PATIENTS_LOG << "Input file Priming read FAILED" << endl;
}
count=1;
//Header
cout \<\< "Room Name Pulse Respir Oxygen" \<\< endl;
cout \<\<"-----------------------------------------------------" \<\< endl;
while (!PATIENTS_IN.eof())
{PATIENTS_IN \>\> FirstName \>\>
LastName \>\> Pulse \>\> Resp \>\> O2Lvl \>\> RoomNum;
//Conversion
pulseint=stoi(Pulse);
respint=stoi(Resp);
O2int=stoi(O2Lvl);
if(pulseint\>100)
{Pulse="High=" + Pulse;
}
else if(pulseint\<60)
{Pulse="Low="+ Pulse;
}
else
{}//Do Nothing
if(respint\>20)
{Resp="High=" + Resp;
}
else if(respint\<12)
{Resp="Low="+ Resp;
}
else
{
}
if(O2int\>100)
{O2Lvl="High=" + O2Lvl;
}
else if(O2int\<92)
{O2Lvl="Low="+ O2Lvl;
}
else
{
}
if(pulseint\>100||pulseint\<60)
{count1++;
}
if(respint\>20||respint\<12)
{count2++;
}
if(O2int\>100||O2int\<92)
{count3++;
}
if(count1==1)
{diag="CHECK--";
check++;}
if(count1==2)
{diag= "ALERT ***";
alert++;}
if(count1==3)
{diag= "CRITICAL***\*\*";
critical++;}
else
{diag="";
}
cout << left <<RoomNum << " " << LastName << ", " << FirstName<< "";
cout << right <<""<<setw(12)<<Pulse <<right
cout << ""<<setw(10) <<Resp <<""<< right<<setw(10) << O2Lvl<<"\n";
}//End While
Pause();
return (0);
}
I have tried messing with the counters, others say they are having run time errors while trying to run the code while I don't get them, as well as alignment issues. I feel like Albert Einstein's definition of insanity.
I am "including" a .tex file. I get the error "TeX capacity exceeded, sorry [input stack size=5000].#nomath ...e#font#warning etc."
The error is located by latex in the line that says
\pic[current plane, draw,fill=orange!50,fill opacity=.5, text
opacity=1,"\footnotesize $\phi$", angle
eccentricity=2.2]{angle=ketplus--origin--psiProjectedEquat}; %je
nachdem, ob der Psi Pfeil links oder rechts von der z-Achse ist, muss
man die Reihenfolge bei "angle=" umkehren }
I should point out that the file that is "included" works when compiled on its own (where the preamble isn't in the masterfile but in the file itself. It seems that the \usepackage[ngerman]{babel} in the masterfile causes the problem.
MWE:
"file.tex":
\documentclass{article}
\usepackage[ngerman]{babel}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsfonts}
\usepackage{tikz}
\usetikzlibrary{positioning,arrows,calc,math,angles,quotes}
\usepackage{blochsphere}
\usepackage{braket}
\usetikzlibrary{arrows.meta}
\begin{document}
\include{file1}
\end{document}
"file1.tex":
\def\rotationSphere{-10} %Drehung im Uhrzeigersinn aus der Standardposition "x-Achse aus Bildebene heraus, y-Achse nach rechts"; 89.9 statt 90 (sonst Division von 0 durch 0)
\def\tiltSphere{10} %0.01 statt 0 da bei 0 Fehler bei der im Paket hinterlegten Rechnung mit Sinus/Cosinus kommen
\def\radiusSphere{2cm}
\def\psiTheta{70} %Winkel Theta
\def\psiPhi{65} %Winkel Phi
%Farbeinstellung als Hinweis für sämtliche color= Befehle
%draw={rgb,255:red,199; green,199; blue,199}
\begin{blochsphere}
[ball=none,radius=\radiusSphere,opacity=1,rotation=\rotationSphere,tilt=\tiltSphere,color=white]
\newcommand\drawLatitudeCircleNew[2][]{
\begingroup
\pgfmathsetmacro\yshift{sin(#2)*\blochsphere#radius}
\pgfmathsetmacro\radius{\blochsphere#radius*cos(#2)}
\drawCircleNew[#1,shift={{0,0,\yshift}},radius=\radius]{0}{0}
\endgroup
}%
\newcommand\drawLongitudeCircleNew[2][]{
\begingroup
\drawCircleNew[#1]{90}{#2+90}
\endgroup
}
\newcommand\drawCircleNew[3][]{
\begingroup
%\setkeys{blochsphere}{#1}
\setDrawingPlane{#2}{#3}
\computeVisibility{#2}{#3}{agamma}{abeta}
\begingroup\edef\tmp{\endgroup%
\noexpand\draw[opacity=0.2,line width=0.8,current plane,on layer=front,\unexpanded\expandafter{\blochsphere#style}] \unexpanded\expandafter{(\agamma-\abeta-0.2:\blochsphere#radius+\the\pgflinewidth*0.5) arc (\agamma-\abeta-0.2:\agamma+\abeta+0.2:\blochsphere#radius+\the\pgflinewidth*0.5)};
\noexpand\draw[current plane,opacity=0.5,line width=0.8,on layer=front,\unexpanded\expandafter{\blochsphere#style}] \unexpanded\expandafter{(\agamma+\abeta:\blochsphere#radius+\the\pgflinewidth*0.5) arc (\agamma+\abeta:\agamma-\abeta+360:\blochsphere#radius+\the\pgflinewidth*0.5)};
} \tmp
\endgroup
}%hier Dicke, Form und Farbe von Longitude/Latitude Circle einstellen
\pgfdeclareradialshading[tikz#ball]{ball}{\pgfqpoint{-10bp}{10bp}}{
color(0bp)=(tikz#ball!90!white);
color(9bp)=(tikz#ball!90!white);
color(18bp)=(tikz#ball!90!white);
color(25bp)=(tikz#ball!90!black);
color(50bp)=(black)
}
\drawBall[ball=3d,radius=\radiusSphere,opacity=1,rotation=\rotationSphere,tilt=\tiltSphere,color=white]
%\drawBallGrid[style={opacity=.3}]{30}{30}
%Vertikale Ebene (als Kreis) zeichnen
%\drawLongitudeCircle[]{\rotationSphere}
\drawLongitudeCircleNew[style={opacity=0.3,line width=0.8}]{-90-0} %Schreibe bei Befehle, die Latitude und Longitude verwenden immer {90-phiTheta} und {-90-phi)}
%Horizontale Ebene (als Kreis) zeichnen
\drawLatitudeCircleNew[style={opacity=0.3,line width=0.8}]{90-90} %style={dashed} falls Linie gestrichelt haben will
%Punkte auf der Kugel definieren (für Achsen)
\labelLatLon[radius=\radiusSphere*1.3]{ket0}{90-0}{-90-0}; %Schreibe bei LatLon Befehl immer {90-phiTheta} und {-90-phi)} wegen Definition von LabelLatLon
\labelLatLon[radius=\radiusSphere]{ket1}{90-180}{-90-0};
\labelLatLon[radius=\radiusSphere]{ketminus}{90-90}{-90-0+180};
\labelLatLon[radius=\radiusSphere*2.2]{ketplus}{90-90}{-90-0};
\labelLatLon[radius=\radiusSphere*1.25]{ketpluspi2}{90-90}{-90-90};
\labelLatLon[radius=\radiusSphere]{ketplus3pi2}{90-90}{-90-90+180};
\labelLatLon{psi}{90-\psiTheta}{-90-\psiPhi};
%Achen zeichnen und markieren
%z-Achse
\draw[-latex,opacity=0.5,line width=0.8] (0,0,0) -- (ket0) node[below right,inner sep=.5mm,opacity=0.5] at (ket0) {\footnotesize $z$};
%Bemerkung: 0,0,0 karthesische Koordinaten; ket0 in 2D Koordinaten auf der Kugeloberfläche
%gepunkteter Teil der z-Achse
\draw[-latex,opacity=0.3,line width=0.8,-] (0,0,0) -- (ketplus3pi2) node[below right,inner sep=.5mm,opacity=0.5] at (ketplus3pi2) {};
%usw.
\draw[-latex,opacity=0.3,line width=0.8,-] (0,0,0) -- (ket1) node[below right,inner sep=.5mm,opacity=0.5] at (ket1) {};
\draw[-latex,opacity=0.3,line width=0.8,-] (0,0,0) -- (ketminus) node[below right,inner sep=.5mm,opacity=0.5] at (ket1) {};
\draw[-latex,opacity=0.5,line width=0.8] (0,0,0) -- (ketplus) node[above left,inner sep=.5mm,opacity=0.5] at (ketplus) {\footnotesize$x$};
\draw[-latex,opacity=0.5,line width=0.8] (0,0,0) -- (ketpluspi2) node[below left,inner sep=0.5mm,opacity=0.5] at (ketpluspi2) {\footnotesize $y$};
%|psi> zeichnen
\draw[-latex,color=orange,line width=2] (0,0,0) -- (psi) node[above]{\footnotesize $\ket{\psi}$};
\def\phitest{65}
\labelLatLon{test}{90-90}{-90-65};
\draw[-latex,color=orange,line width=2] (0,0,0) -- (test) node[above]{\footnotesize $\ket{test}$};
%Winkel zeichnen
\coordinate (origin) at (0,0,0);
{
%Projektion zeichnen - cosinus verwendet
\setDrawingPlane{0}{0}
\draw[current plane,dashed] (0,0,0) -- (180+\psiPhi:{cos(90-\psiTheta)*\radiusSphere}) coordinate (psiProjectedEquat) -- (psi); %Winkel:Länge Polarkoordinaten
%Winkel schattieren (phi)
\pic[current plane, draw,fill=orange!50,fill opacity=.5, text opacity=1,"\footnotesize $\phi$", angle eccentricity=2.2]{angle=ketplus--origin--psiProjectedEquat}; %je nachdem, ob der Psi Pfeil links oder rechts von der z-Achse ist, muss man die Reihenfolge bei "angle=" umkehren
}
{ \setLongitudinalDrawingPlane{-90-\psiPhi}
%Winkel schattieren (theta)
\pic[current plane, draw,fill=orange!50,fill opacity=.5, text opacity=1,"\footnotesize $\theta$", angle eccentricity=1.5]{angle=ket0--origin--psi}; %je nachdem, ob der Psi Pfeil links oder rechts von der z-Achse ist, muss man die Reihenfolge bei "angle=" umkehren
}
\end{blochsphere}
As you've noticed, the combination of your tikz picture and babel causes the problem. You can fix this by loading the babel tikz library:
\documentclass{article}
\usepackage[ngerman]{babel}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsfonts}
\usepackage{tikz}
\usetikzlibrary{positioning,arrows,calc,math,angles,quotes}
\usepackage{blochsphere}
\usepackage{braket}
\usetikzlibrary{arrows.meta,babel}
\begin{document}
\include{file1}
\end{document}
Hello im doing a project for my university in latex and came accross this problem and nothing to fix it.
Basically there is this white space bevore the beginning of each paragraph. Below is my latex code from this sheet.
einem Ausgabeneuron. Gewichte in Neuronalen Netzen sind reelle Zahlen, unter denen man sich die Wichtigkeit der jeweiligen Eingabe vorstellen kann. Ändert man die Gewichte der einzelnen Eingabeneuronen, beeinflusst man somit die spätere Aktivierung des Ausgabeneurons. Die Ausgabe $y$ wird bestimmt durch die Aktivierungsfunktion des Ausgabeneurons und ist dabei wie folgt definiert: \\
%Output gleichung
\begin{equation}
y =
\begin{cases}
0, & \text{wenn}\ $$\sum_{i} w_{i}x_{i} \leq Schwellwert$$ \\
1, & \text{andernfalls}
\end{cases}
\end{equation}\\
Dabei ist der Schwellwert Teil des jeweiligen Neurons. Wie bei den Eingaben und Gewichtungen handelt es sich bei dem Schwellwert auch um eine reelle Zahl, welche anpassbar ist, um unterschiedliche Ergebnisse zu erzwingen. Worin besteht nun der Unterschied zu einem Multilayer Perzeptron? \\
Die Aktivierungsfunktion eines Multilayer Perzeptrons springt nicht zwischen 0 und 1, wie in (1) definiert sondern verhält sich stetig. \\
Das Singlelayer Perzeptron ist in der Lage, linear separierbare Probleme, wie z.B. die AND Funktion, zu lösen. Hier lassen sich die Resultatrelationen klar durch eine Gerade trennen. Bei der XOR Funktion reicht eine Gerade nicht mehr aus, ein Singlelayer Perzeptron wäre also nicht in der Lage, die XOR Funktion zu lösen.
Add \usepackage{parskip} to your preamble. For further customisation options see the parskip documentation.
I have a problem with the RTOS firmware on the esp8266 (I have a esp12e), after flashing the firmware, reading from uart, it keeps stuck with those lines:
ets Jan 8 2013,rst cause:2, boot mode:(3,0)
load 0x40100000, len 31584, room 16
tail 0
chksum 0x24
load 0x3ffe8000, len 944, room 8
tail 8
chksum 0x9e
load 0x3ffe83b0, len 1080, room 0
tail 8
chksum 0x60
csum 0x60
Now I will explain my HW setup:
GPIO15 -> Gnd
EN -> Vcc
GPIO0 -> Gnd (when flashing)
GPIO0 -> Vcc (normal mode)
For the toolchain I've followed this tutorial and it works well:
http://microcontrollerkits.blogspot.it/2015/12/esp8266-eclipse-development.html
Then I started doing my RTOS blink example, I post my user_main.c code here:
#include "esp_common.h"
#include "gpio.h"
void task2(void *pvParameters)
{
printf("Hello, welcome to client!\r\n");
while(1)
{
// Delay and turn on
vTaskDelay (300/portTICK_RATE_MS);
GPIO_OUTPUT_SET (5, 1);
// Delay and LED off
vTaskDelay (300/portTICK_RATE_MS);
GPIO_OUTPUT_SET (5, 0);
}
}
/******************************************************************************
* FunctionName : user_rf_cal_sector_set
* Description : SDK just reversed 4 sectors, used for rf init data and paramters.
* We add this function to force users to set rf cal sector, since
* we don't know which sector is free in user's application.
* sector map for last several sectors : ABCCC
* A : rf cal
* B : rf init data
* C : sdk parameters
* Parameters : none
* Returns : rf cal sector
*******************************************************************************/
uint32 user_rf_cal_sector_set(void)
{
flash_size_map size_map = system_get_flash_size_map();
uint32 rf_cal_sec = 0;
switch (size_map) {
case FLASH_SIZE_4M_MAP_256_256:
rf_cal_sec = 128 - 5;
break;
case FLASH_SIZE_8M_MAP_512_512:
rf_cal_sec = 256 - 5;
break;
case FLASH_SIZE_16M_MAP_512_512:
case FLASH_SIZE_16M_MAP_1024_1024:
rf_cal_sec = 512 - 5;
break;
case FLASH_SIZE_32M_MAP_512_512:
case FLASH_SIZE_32M_MAP_1024_1024:
rf_cal_sec = 1024 - 5;
break;
default:
rf_cal_sec = 0;
break;
}
return rf_cal_sec;
}
/******************************************************************************
* FunctionName : user_init
* Description : entry of user application, init user function here
* Parameters : none
* Returns : none
*******************************************************************************/
void user_init(void)
{
uart_init_new();
printf("SDK version:%s\n", system_get_sdk_version());
// Config pin as GPIO5
PIN_FUNC_SELECT (PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
xTaskCreate(task2, "tsk2", 256, NULL, 2, NULL);
}
I also post the flash command, the first executed one time, the second every time I modify the code:
c:/Espressif/utils/ESP8266/esptool.exe -p COM3 write_flash -ff 40m -fm qio -fs 32m 0x3FC000 c:/Espressif/ESP8266_RTOS_SDK/bin/esp_init_data_default.bin 0x3FE000 c:/Espressif/ESP8266_RTOS_SDK/bin/blank.bin 0x7E000 c:/Espressif/ESP8266_RTOS_SDK/bin/blank.bin
c:/Espressif/utils/ESP8266/esptool.exe -p COM3 -b 256000 write_flash -ff 40m -fm qio -fs 32m 0x00000 firmware/eagle.flash.bin 0x40000 firmware/eagle.irom0text.bin
There is something wrong? I really don't understand why it doesn't work.
When I try the NON-OS example they works very well.
I had the same problem as you. This issue is caused by the incorrect address of the eagle.irom0text.bin .
So I changed the address of the eagle.irom0text.bin from 0x40000 (0x10000) to 0x20000 and it worked well for me.
[RTOS SDK version: 1.4.2(f57d61a)]
The correct flash codes in the common_rtos.mk (ESP-12E)
for flashinit
flashinit:
$(vecho) "Flash init data default and blank data."
$(ESPTOOL) -p $(ESPPORT) write_flash $(flashimageoptions) 0x3fc000 $(SDK_BASE)/bin/esp_init_data_default.bin
$(ESPTOOL) -p $(ESPPORT) write_flash $(flashimageoptions) 0x3fe000 $(SDK_BASE)/bin/blank.bin
for flash:
flash: all
#ifeq ($(app), 0)
$(ESPTOOL) -p $(ESPPORT) -b $(ESPBAUD) write_flash $(flashimageoptions) 0x00000 $(FW_BASE)/eagle.flash.bin 0x20000 $(FW_BASE)/eagle.irom0text.bin
else
ifeq ($(boot), none)
$(ESPTOOL) -p $(ESPPORT) -b $(ESPBAUD) write_flash $(flashimageoptions) 0x00000 $(FW_BASE)/eagle.flash.bin 0x20000 $(FW_BASE)/eagle.irom0text.bin
else
$(ESPTOOL) -p $(ESPPORT) -b $(ESPBAUD) write_flash $(flashimageoptions) $(addr) $(FW_BASE)/upgrade/$(BIN_NAME).bin
endif
endif
I am having horrible time trying to figure out why my sync. code gets deadlocked when using pthread library. Using winapi primitives is instead of pthread works with no problems. Using c++11 threading also works fine (unless compiled with visual studio 2012 service pack 3, there it just crashes - Microsoft accepted it as a bug.) Using pthread however proves to be a problem - at least running in on linux machine, haven't had a chance to try different OS.
I've written a simple program which illustrates the issue. The code is just showing the deadlock - I am well aware the design is pretty poor and can be written much better.
typedef struct _pthread_event
{
pthread_mutex_t Mutex;
pthread_cond_t Condition;
unsigned char State;
} pthread_event;
void pthread_event_create( pthread_event * ev , unsigned char init_state )
{
pthread_mutex_init( &ev->Mutex , 0 );
pthread_cond_init( &ev->Condition , 0 );
ev->State = init_state;
}
void pthread_event_destroy( pthread_event * ev )
{
pthread_cond_destroy( &ev->Condition );
pthread_mutex_destroy( &ev->Mutex );
}
void pthread_event_set( pthread_event * ev , unsigned char state )
{
pthread_mutex_lock( &ev->Mutex );
ev->State = state;
pthread_mutex_unlock( &ev->Mutex );
pthread_cond_broadcast( &ev->Condition );
}
unsigned char pthread_event_get( pthread_event * ev )
{
unsigned char result;
pthread_mutex_lock( &ev->Mutex );
result = ev->State;
pthread_mutex_unlock( &ev->Mutex );
return result;
}
unsigned char pthread_event_wait( pthread_event * ev , unsigned char state , unsigned int timeout_ms )
{
struct timeval time_now;
struct timespec timeout_time;
unsigned char result;
gettimeofday( &time_now , NULL );
timeout_time.tv_sec = time_now.tv_sec + ( timeout_ms / 1000 );
timeout_time.tv_nsec = time_now.tv_usec * 1000 + ( ( timeout_ms % 1000 ) * 1000000 );
pthread_mutex_lock( &ev->Mutex );
while ( ev->State != state )
if ( ETIMEDOUT == pthread_cond_timedwait( &ev->Condition , &ev->Mutex , &timeout_time ) ) break;
result = ev->State;
pthread_mutex_unlock( &ev->Mutex );
return result;
}
static pthread_t thread_1;
static pthread_t thread_2;
static pthread_event data_ready;
static pthread_event data_needed;
void * thread_fx1( void * c )
{
for ( ; ; )
{
pthread_event_wait( &data_needed , 1 , 90 );
pthread_event_set( &data_needed , 0 );
usleep( 100000 );
pthread_event_set( &data_ready , 1 );
printf( "t1: tick\n" );
}
}
void * thread_fx2( void * c )
{
for ( ; ; )
{
pthread_event_wait( &data_ready , 1 , 50 );
pthread_event_set( &data_ready , 0 );
pthread_event_set( &data_needed , 1 );
usleep( 100000 );
printf( "t2: tick\n" );
}
}
int main( int argc , char * argv[] )
{
pthread_event_create( &data_ready , 0 );
pthread_event_create( &data_needed , 0 );
pthread_create( &thread_1 , NULL , thread_fx1 , 0 );
pthread_create( &thread_2 , NULL , thread_fx2 , 0 );
pthread_join( thread_1 , NULL );
pthread_join( thread_2 , NULL );
pthread_event_destroy( &data_ready );
pthread_event_destroy( &data_needed );
return 0;
}
Basically two threads signaling each other - start doing something, and doing their own thing even if not signaled after a short timeout.
Any idea what it going wrong there?
Thanks.
The problem is the timeout_time parameter to pthread_cond_timedwait(). The way you increment it is eventually and quite soon going to have an invalid value there with nanosecond part bigger than or equal to billion. In this case pthread_cond_timedwait() perhaps return with EINVAL, and probably actually before waiting for the condition.
The problem can be found very quickly with valgrind --tool=helgrind ./test_prog (quite soon it said it had already detected 10000000 errors and gave up counting):
bash$ gcc -Werror -Wall -g test.c -o test -lpthread && valgrind --tool=helgrind ./test
==3035== Helgrind, a thread error detector
==3035== Copyright (C) 2007-2012, and GNU GPL'd, by OpenWorks LLP et al.
==3035== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==3035== Command: ./test
==3035==
t1: tick
t2: tick
t2: tick
t1: tick
t2: tick
t1: tick
t1: tick
t2: tick
t1: tick
t2: tick
t1: tick
==3035== ---Thread-Announcement------------------------------------------
==3035==
==3035== Thread #2 was created
==3035== at 0x41843C8: clone (clone.S:110)
==3035==
==3035== ----------------------------------------------------------------
==3035==
==3035== Thread #2's call to pthread_cond_timedwait failed
==3035== with error code 22 (EINVAL: Invalid argument)
==3035== at 0x402DB03: pthread_cond_timedwait_WRK (hg_intercepts.c:784)
==3035== by 0x8048910: pthread_event_wait (test.c:65)
==3035== by 0x8048965: thread_fx1 (test.c:80)
==3035== by 0x402E437: mythread_wrapper (hg_intercepts.c:219)
==3035== by 0x407DD77: start_thread (pthread_create.c:311)
==3035== by 0x41843DD: clone (clone.S:131)
==3035==
t2: tick
==3035==
==3035== More than 10000000 total errors detected. I'm not reporting any more.
==3035== Final error counts will be inaccurate. Go fix your program!
==3035== Rerun with --error-limit=no to disable this cutoff. Note
==3035== that errors may occur in your program without prior warning from
==3035== Valgrind, because errors are no longer being displayed.
==3035==
^C==3035==
==3035== For counts of detected and suppressed errors, rerun with: -v
==3035== Use --history-level=approx or =none to gain increased speed, at
==3035== the cost of reduced accuracy of conflicting-access information
==3035== ERROR SUMMARY: 10000000 errors from 1 contexts (suppressed: 412 from 109)
Killed
There is also two other minor comments:
For improved correctness, in your pthread_event_set() you could have the condition variable broadcast be done before mutex unlock (the effect of wrong ordering basically could break the determinism of the scheduling; helgrind complains about this issue too);
you could safely drop the mutex locking in pthread_event_get() to return the value of ev->State - this should be atomic operation.